forked from friendica/friendica-addons
Compare commits
82 commits
mat/ratioe
...
2024.09-rc
Author | SHA1 | Date | |
---|---|---|---|
Hypolite Petovan | 6a2c0d974e | ||
Michael | f52bb75c97 | ||
Hypolite Petovan | 8989e0dab6 | ||
Michael | 7fcbd76c6b | ||
heluecht | dc0b79bed1 | ||
a0c727ac35 | |||
heluecht | e133a693c2 | ||
Hypolite Petovan | aa5130247b | ||
Hypolite Petovan | aeefb92926 | ||
Michael | c22e0ae831 | ||
Tobias Diekershoff | f499875f5b | ||
Michael | 6a1cbe9040 | ||
Tobias Diekershoff | 6980d3b02b | ||
Tobias Diekershoff | e89b5b1466 | ||
Tobias Diekershoff | 5638e7f065 | ||
Michael | 4165479079 | ||
Tobias Diekershoff | fca2d609c9 | ||
Michael | 8b694fbb4c | ||
Tobias Diekershoff | 5a9dafec70 | ||
Michael | 586ebe9699 | ||
Tobias Diekershoff | 10bd219bd1 | ||
Michael | 08c17c9dd4 | ||
Tobias Diekershoff | feb7722f72 | ||
Michael | f8f63532f4 | ||
Tobias Diekershoff | ef37aa60e3 | ||
Michael | 6f3ba10466 | ||
Tobias Diekershoff | 778b9e3f61 | ||
loma-one | 10521115c4 | ||
Tobias Diekershoff | 956233ff1d | ||
Michael | 14e1c96775 | ||
Tobias Diekershoff | 7a7dbb579d | ||
loma-one | 712edf4236 | ||
Tobias Diekershoff | 5c0cddfc1d | ||
loma-one | 3dc77b2102 | ||
Tobias Diekershoff | 6c43a14198 | ||
Michael | 0dfb345f85 | ||
Tobias Diekershoff | ab837dfec5 | ||
Michael | 2f9076bffd | ||
Tobias Diekershoff | 454e9834bf | ||
Michael | 50930c301d | ||
Philipp Holzer | 3457ab2f3f | ||
Philipp Holzer | 276c27678f | ||
Tobias Diekershoff | cd95ca1a0a | ||
Tobias Diekershoff | 5c04e7136f | ||
heluecht | 179382d8a9 | ||
Tobias Diekershoff | a55f80cb39 | ||
Tobias Diekershoff | 4ad7d61893 | ||
Michael | 4bfdb45e81 | ||
Tobias Diekershoff | 4414471100 | ||
46a55f13f7 | |||
Tobias Diekershoff | a97cccb6b2 | ||
Michael | c0535db742 | ||
Tobias Diekershoff | 0c04b086cb | ||
589cf712cc | |||
heluecht | ce53e48cb2 | ||
f3db763c59 | |||
Tobias Diekershoff | b0a95ca2d2 | ||
Hannes Heute | b2108c7a4c | ||
Hypolite Petovan | abca07b29d | ||
hankg | 14e7413eb2 | ||
Hypolite Petovan | 39567cf701 | ||
Tobias Diekershoff | 2789e880dc | ||
Tobias Diekershoff | 1556ebfb33 | ||
3e1b98d5d9 | |||
Tobias Diekershoff | ed07c987a6 | ||
Michael | af868f45ab | ||
Tobias Diekershoff | 7f0cf2527c | ||
Michael | 9525259fc8 | ||
Tobias Diekershoff | f7ca152754 | ||
Michael | 6f56932f12 | ||
Tobias Diekershoff | b6f2e7dd50 | ||
Michael | fa16adccaf | ||
Tobias Diekershoff | 252f3e222a | ||
Michael | 231d830db0 | ||
Tobias Diekershoff | 27e362213f | ||
Michael | 734d35d22b | ||
Hypolite Petovan | 722fdc07fb | ||
Michael | 77c471ab4d | ||
heluecht | bac665864e | ||
Tobias Diekershoff | c7f4d183b1 | ||
Hypolite Petovan | 010261c1dc | ||
Philipp Holzer | 3f26f9785e |
|
@ -4,6 +4,9 @@ pipeline:
|
||||||
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:
|
||||||
|
|
|
@ -9,6 +9,9 @@ pipeline:
|
||||||
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:
|
||||||
|
|
|
@ -4,6 +4,9 @@ pipeline:
|
||||||
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:
|
||||||
|
|
|
@ -21,6 +21,9 @@ pipeline:
|
||||||
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:
|
||||||
|
|
|
@ -9,6 +9,9 @@ pipeline:
|
||||||
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:
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.';
|
||||||
|
|
18
advancedcontentfilter/vendor/autoload.php
vendored
18
advancedcontentfilter/vendor/autoload.php
vendored
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
359
advancedcontentfilter/vendor/composer/InstalledVersions.php
vendored
Normal file
359
advancedcontentfilter/vendor/composer/InstalledVersions.php
vendored
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,11 +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',
|
'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',
|
||||||
|
@ -154,7 +155,6 @@ return array(
|
||||||
'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',
|
||||||
|
@ -188,7 +188,6 @@ 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\\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',
|
||||||
|
@ -197,7 +196,6 @@ return array(
|
||||||
'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',
|
||||||
'Symfony\\Component\\Cache\\Traits\\LazyValue' => $vendorDir . '/symfony/cache/Traits/PhpFilesTrait.php',
|
|
||||||
'Symfony\\Component\\Cache\\Traits\\MemcachedTrait' => $vendorDir . '/symfony/cache/Traits/MemcachedTrait.php',
|
'Symfony\\Component\\Cache\\Traits\\MemcachedTrait' => $vendorDir . '/symfony/cache/Traits/MemcachedTrait.php',
|
||||||
'Symfony\\Component\\Cache\\Traits\\PdoTrait' => $vendorDir . '/symfony/cache/Traits/PdoTrait.php',
|
'Symfony\\Component\\Cache\\Traits\\PdoTrait' => $vendorDir . '/symfony/cache/Traits/PdoTrait.php',
|
||||||
'Symfony\\Component\\Cache\\Traits\\PhpArrayTrait' => $vendorDir . '/symfony/cache/Traits/PhpArrayTrait.php',
|
'Symfony\\Component\\Cache\\Traits\\PhpArrayTrait' => $vendorDir . '/symfony/cache/Traits/PhpArrayTrait.php',
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
// 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(
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
// 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(
|
||||||
|
@ -16,7 +16,7 @@ return array(
|
||||||
'Slim\\' => array($vendorDir . '/slim/slim/Slim'),
|
'Slim\\' => array($vendorDir . '/slim/slim/Slim'),
|
||||||
'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'),
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -83,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 (
|
||||||
|
@ -102,6 +102,7 @@ class ComposerStaticInitAdvancedContentFilterAddon
|
||||||
|
|
||||||
public static $classMap = array (
|
public static $classMap = array (
|
||||||
'Attribute' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
|
'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',
|
||||||
|
@ -249,7 +250,6 @@ class ComposerStaticInitAdvancedContentFilterAddon
|
||||||
'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',
|
||||||
|
@ -283,7 +283,6 @@ 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\\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',
|
||||||
|
@ -292,7 +291,6 @@ class ComposerStaticInitAdvancedContentFilterAddon
|
||||||
'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',
|
||||||
'Symfony\\Component\\Cache\\Traits\\LazyValue' => __DIR__ . '/..' . '/symfony/cache/Traits/PhpFilesTrait.php',
|
|
||||||
'Symfony\\Component\\Cache\\Traits\\MemcachedTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/MemcachedTrait.php',
|
'Symfony\\Component\\Cache\\Traits\\MemcachedTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/MemcachedTrait.php',
|
||||||
'Symfony\\Component\\Cache\\Traits\\PdoTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/PdoTrait.php',
|
'Symfony\\Component\\Cache\\Traits\\PdoTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/PdoTrait.php',
|
||||||
'Symfony\\Component\\Cache\\Traits\\PhpArrayTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/PhpArrayTrait.php',
|
'Symfony\\Component\\Cache\\Traits\\PhpArrayTrait' => __DIR__ . '/..' . '/symfony/cache/Traits/PhpArrayTrait.php',
|
||||||
|
|
2354
advancedcontentfilter/vendor/composer/installed.json
vendored
2354
advancedcontentfilter/vendor/composer/installed.json
vendored
File diff suppressed because it is too large
Load diff
203
advancedcontentfilter/vendor/composer/installed.php
vendored
Normal file
203
advancedcontentfilter/vendor/composer/installed.php
vendored
Normal 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,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
26
advancedcontentfilter/vendor/composer/platform_check.php
vendored
Normal file
26
advancedcontentfilter/vendor/composer/platform_check.php
vendored
Normal 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
|
||||||
|
);
|
||||||
|
}
|
|
@ -1,12 +0,0 @@
|
||||||
; This file is for unifying the coding style for different editors and IDEs.
|
|
||||||
; More information at http://editorconfig.org
|
|
||||||
|
|
||||||
root = true
|
|
||||||
|
|
||||||
[*]
|
|
||||||
charset = utf-8
|
|
||||||
indent_size = 4
|
|
||||||
indent_style = space
|
|
||||||
end_of_line = lf
|
|
||||||
insert_final_newline = true
|
|
||||||
trim_trailing_whitespace = true
|
|
|
@ -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.
|
|
|
@ -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.
|
|
|
@ -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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Psr\SimpleCache;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface used for all types of exceptions thrown by the implementing library.
|
|
||||||
*/
|
|
||||||
interface CacheException
|
|
||||||
{
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
{
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
composer.lock
|
|
||||||
phpunit.xml
|
|
||||||
vendor/
|
|
|
@ -1,47 +0,0 @@
|
||||||
<?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\Tests\Adapter;
|
|
||||||
|
|
||||||
use Symfony\Component\Cache\Adapter\RedisAdapter;
|
|
||||||
|
|
||||||
abstract class AbstractRedisAdapterTest extends AdapterTestCase
|
|
||||||
{
|
|
||||||
protected $skippedTests = [
|
|
||||||
'testExpiration' => 'Testing expiration slows down the test suite',
|
|
||||||
'testHasItemReturnsFalseWhenDeferredItemIsExpired' => 'Testing expiration slows down the test suite',
|
|
||||||
'testDefaultLifeTime' => 'Testing expiration slows down the test suite',
|
|
||||||
];
|
|
||||||
|
|
||||||
protected static $redis;
|
|
||||||
|
|
||||||
public function createCachePool($defaultLifetime = 0)
|
|
||||||
{
|
|
||||||
return new RedisAdapter(self::$redis, str_replace('\\', '.', __CLASS__), $defaultLifetime);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function setUpBeforeClass()
|
|
||||||
{
|
|
||||||
if (!\extension_loaded('redis')) {
|
|
||||||
self::markTestSkipped('Extension redis required.');
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
(new \Redis())->connect(getenv('REDIS_HOST'));
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
self::markTestSkipped($e->getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function tearDownAfterClass()
|
|
||||||
{
|
|
||||||
self::$redis = null;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,175 +0,0 @@
|
||||||
<?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\Tests\Adapter;
|
|
||||||
|
|
||||||
use Cache\IntegrationTests\CachePoolTest;
|
|
||||||
use Psr\Cache\CacheItemPoolInterface;
|
|
||||||
use Symfony\Component\Cache\PruneableInterface;
|
|
||||||
|
|
||||||
abstract class AdapterTestCase extends CachePoolTest
|
|
||||||
{
|
|
||||||
protected function setUp()
|
|
||||||
{
|
|
||||||
parent::setUp();
|
|
||||||
|
|
||||||
if (!\array_key_exists('testDeferredSaveWithoutCommit', $this->skippedTests) && \defined('HHVM_VERSION')) {
|
|
||||||
$this->skippedTests['testDeferredSaveWithoutCommit'] = 'Destructors are called late on HHVM.';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!\array_key_exists('testPrune', $this->skippedTests) && !$this->createCachePool() instanceof PruneableInterface) {
|
|
||||||
$this->skippedTests['testPrune'] = 'Not a pruneable cache pool.';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testDefaultLifeTime()
|
|
||||||
{
|
|
||||||
if (isset($this->skippedTests[__FUNCTION__])) {
|
|
||||||
$this->markTestSkipped($this->skippedTests[__FUNCTION__]);
|
|
||||||
}
|
|
||||||
|
|
||||||
$cache = $this->createCachePool(2);
|
|
||||||
|
|
||||||
$item = $cache->getItem('key.dlt');
|
|
||||||
$item->set('value');
|
|
||||||
$cache->save($item);
|
|
||||||
sleep(1);
|
|
||||||
|
|
||||||
$item = $cache->getItem('key.dlt');
|
|
||||||
$this->assertTrue($item->isHit());
|
|
||||||
|
|
||||||
sleep(2);
|
|
||||||
$item = $cache->getItem('key.dlt');
|
|
||||||
$this->assertFalse($item->isHit());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testExpiration()
|
|
||||||
{
|
|
||||||
if (isset($this->skippedTests[__FUNCTION__])) {
|
|
||||||
$this->markTestSkipped($this->skippedTests[__FUNCTION__]);
|
|
||||||
}
|
|
||||||
|
|
||||||
$cache = $this->createCachePool();
|
|
||||||
$cache->save($cache->getItem('k1')->set('v1')->expiresAfter(2));
|
|
||||||
$cache->save($cache->getItem('k2')->set('v2')->expiresAfter(366 * 86400));
|
|
||||||
|
|
||||||
sleep(3);
|
|
||||||
$item = $cache->getItem('k1');
|
|
||||||
$this->assertFalse($item->isHit());
|
|
||||||
$this->assertNull($item->get(), "Item's value must be null when isHit() is false.");
|
|
||||||
|
|
||||||
$item = $cache->getItem('k2');
|
|
||||||
$this->assertTrue($item->isHit());
|
|
||||||
$this->assertSame('v2', $item->get());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testNotUnserializable()
|
|
||||||
{
|
|
||||||
if (isset($this->skippedTests[__FUNCTION__])) {
|
|
||||||
$this->markTestSkipped($this->skippedTests[__FUNCTION__]);
|
|
||||||
}
|
|
||||||
|
|
||||||
$cache = $this->createCachePool();
|
|
||||||
|
|
||||||
$item = $cache->getItem('foo');
|
|
||||||
$cache->save($item->set(new NotUnserializable()));
|
|
||||||
|
|
||||||
$item = $cache->getItem('foo');
|
|
||||||
$this->assertFalse($item->isHit());
|
|
||||||
|
|
||||||
foreach ($cache->getItems(['foo']) as $item) {
|
|
||||||
}
|
|
||||||
$cache->save($item->set(new NotUnserializable()));
|
|
||||||
|
|
||||||
foreach ($cache->getItems(['foo']) as $item) {
|
|
||||||
}
|
|
||||||
$this->assertFalse($item->isHit());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testPrune()
|
|
||||||
{
|
|
||||||
if (isset($this->skippedTests[__FUNCTION__])) {
|
|
||||||
$this->markTestSkipped($this->skippedTests[__FUNCTION__]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!method_exists($this, 'isPruned')) {
|
|
||||||
$this->fail('Test classes for pruneable caches must implement `isPruned($cache, $name)` method.');
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @var PruneableInterface|CacheItemPoolInterface $cache */
|
|
||||||
$cache = $this->createCachePool();
|
|
||||||
|
|
||||||
$doSet = function ($name, $value, \DateInterval $expiresAfter = null) use ($cache) {
|
|
||||||
$item = $cache->getItem($name);
|
|
||||||
$item->set($value);
|
|
||||||
|
|
||||||
if ($expiresAfter) {
|
|
||||||
$item->expiresAfter($expiresAfter);
|
|
||||||
}
|
|
||||||
|
|
||||||
$cache->save($item);
|
|
||||||
};
|
|
||||||
|
|
||||||
$doSet('foo', 'foo-val', new \DateInterval('PT05S'));
|
|
||||||
$doSet('bar', 'bar-val', new \DateInterval('PT10S'));
|
|
||||||
$doSet('baz', 'baz-val', new \DateInterval('PT15S'));
|
|
||||||
$doSet('qux', 'qux-val', new \DateInterval('PT20S'));
|
|
||||||
|
|
||||||
sleep(30);
|
|
||||||
$cache->prune();
|
|
||||||
$this->assertTrue($this->isPruned($cache, 'foo'));
|
|
||||||
$this->assertTrue($this->isPruned($cache, 'bar'));
|
|
||||||
$this->assertTrue($this->isPruned($cache, 'baz'));
|
|
||||||
$this->assertTrue($this->isPruned($cache, 'qux'));
|
|
||||||
|
|
||||||
$doSet('foo', 'foo-val');
|
|
||||||
$doSet('bar', 'bar-val', new \DateInterval('PT20S'));
|
|
||||||
$doSet('baz', 'baz-val', new \DateInterval('PT40S'));
|
|
||||||
$doSet('qux', 'qux-val', new \DateInterval('PT80S'));
|
|
||||||
|
|
||||||
$cache->prune();
|
|
||||||
$this->assertFalse($this->isPruned($cache, 'foo'));
|
|
||||||
$this->assertFalse($this->isPruned($cache, 'bar'));
|
|
||||||
$this->assertFalse($this->isPruned($cache, 'baz'));
|
|
||||||
$this->assertFalse($this->isPruned($cache, 'qux'));
|
|
||||||
|
|
||||||
sleep(30);
|
|
||||||
$cache->prune();
|
|
||||||
$this->assertFalse($this->isPruned($cache, 'foo'));
|
|
||||||
$this->assertTrue($this->isPruned($cache, 'bar'));
|
|
||||||
$this->assertFalse($this->isPruned($cache, 'baz'));
|
|
||||||
$this->assertFalse($this->isPruned($cache, 'qux'));
|
|
||||||
|
|
||||||
sleep(30);
|
|
||||||
$cache->prune();
|
|
||||||
$this->assertFalse($this->isPruned($cache, 'foo'));
|
|
||||||
$this->assertTrue($this->isPruned($cache, 'baz'));
|
|
||||||
$this->assertFalse($this->isPruned($cache, 'qux'));
|
|
||||||
|
|
||||||
sleep(30);
|
|
||||||
$cache->prune();
|
|
||||||
$this->assertFalse($this->isPruned($cache, 'foo'));
|
|
||||||
$this->assertTrue($this->isPruned($cache, 'qux'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class NotUnserializable implements \Serializable
|
|
||||||
{
|
|
||||||
public function serialize()
|
|
||||||
{
|
|
||||||
return serialize(123);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function unserialize($ser)
|
|
||||||
{
|
|
||||||
throw new \Exception(__CLASS__);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,124 +0,0 @@
|
||||||
<?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\Tests\Adapter;
|
|
||||||
|
|
||||||
use Psr\Log\NullLogger;
|
|
||||||
use Symfony\Component\Cache\Adapter\ApcuAdapter;
|
|
||||||
|
|
||||||
class ApcuAdapterTest extends AdapterTestCase
|
|
||||||
{
|
|
||||||
protected $skippedTests = [
|
|
||||||
'testExpiration' => 'Testing expiration slows down the test suite',
|
|
||||||
'testHasItemReturnsFalseWhenDeferredItemIsExpired' => 'Testing expiration slows down the test suite',
|
|
||||||
'testDefaultLifeTime' => 'Testing expiration slows down the test suite',
|
|
||||||
];
|
|
||||||
|
|
||||||
public function createCachePool($defaultLifetime = 0)
|
|
||||||
{
|
|
||||||
if (!\function_exists('apcu_fetch') || !filter_var(ini_get('apc.enabled'), \FILTER_VALIDATE_BOOLEAN)) {
|
|
||||||
$this->markTestSkipped('APCu extension is required.');
|
|
||||||
}
|
|
||||||
if ('cli' === \PHP_SAPI && !filter_var(ini_get('apc.enable_cli'), \FILTER_VALIDATE_BOOLEAN)) {
|
|
||||||
if ('testWithCliSapi' !== $this->getName()) {
|
|
||||||
$this->markTestSkipped('apc.enable_cli=1 is required.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ('\\' === \DIRECTORY_SEPARATOR) {
|
|
||||||
$this->markTestSkipped('Fails transiently on Windows.');
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ApcuAdapter(str_replace('\\', '.', __CLASS__), $defaultLifetime);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testUnserializable()
|
|
||||||
{
|
|
||||||
$pool = $this->createCachePool();
|
|
||||||
|
|
||||||
$item = $pool->getItem('foo');
|
|
||||||
$item->set(function () {});
|
|
||||||
|
|
||||||
$this->assertFalse($pool->save($item));
|
|
||||||
|
|
||||||
$item = $pool->getItem('foo');
|
|
||||||
$this->assertFalse($item->isHit());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testVersion()
|
|
||||||
{
|
|
||||||
$namespace = str_replace('\\', '.', static::class);
|
|
||||||
|
|
||||||
$pool1 = new ApcuAdapter($namespace, 0, 'p1');
|
|
||||||
|
|
||||||
$item = $pool1->getItem('foo');
|
|
||||||
$this->assertFalse($item->isHit());
|
|
||||||
$this->assertTrue($pool1->save($item->set('bar')));
|
|
||||||
|
|
||||||
$item = $pool1->getItem('foo');
|
|
||||||
$this->assertTrue($item->isHit());
|
|
||||||
$this->assertSame('bar', $item->get());
|
|
||||||
|
|
||||||
$pool2 = new ApcuAdapter($namespace, 0, 'p2');
|
|
||||||
|
|
||||||
$item = $pool2->getItem('foo');
|
|
||||||
$this->assertFalse($item->isHit());
|
|
||||||
$this->assertNull($item->get());
|
|
||||||
|
|
||||||
$item = $pool1->getItem('foo');
|
|
||||||
$this->assertFalse($item->isHit());
|
|
||||||
$this->assertNull($item->get());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testNamespace()
|
|
||||||
{
|
|
||||||
$namespace = str_replace('\\', '.', static::class);
|
|
||||||
|
|
||||||
$pool1 = new ApcuAdapter($namespace.'_1', 0, 'p1');
|
|
||||||
|
|
||||||
$item = $pool1->getItem('foo');
|
|
||||||
$this->assertFalse($item->isHit());
|
|
||||||
$this->assertTrue($pool1->save($item->set('bar')));
|
|
||||||
|
|
||||||
$item = $pool1->getItem('foo');
|
|
||||||
$this->assertTrue($item->isHit());
|
|
||||||
$this->assertSame('bar', $item->get());
|
|
||||||
|
|
||||||
$pool2 = new ApcuAdapter($namespace.'_2', 0, 'p1');
|
|
||||||
|
|
||||||
$item = $pool2->getItem('foo');
|
|
||||||
$this->assertFalse($item->isHit());
|
|
||||||
$this->assertNull($item->get());
|
|
||||||
|
|
||||||
$item = $pool1->getItem('foo');
|
|
||||||
$this->assertTrue($item->isHit());
|
|
||||||
$this->assertSame('bar', $item->get());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testWithCliSapi()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
// disable PHPUnit error handler to mimic a production environment
|
|
||||||
$isCalled = false;
|
|
||||||
set_error_handler(function () use (&$isCalled) {
|
|
||||||
$isCalled = true;
|
|
||||||
});
|
|
||||||
$pool = new ApcuAdapter(str_replace('\\', '.', __CLASS__));
|
|
||||||
$pool->setLogger(new NullLogger());
|
|
||||||
|
|
||||||
$item = $pool->getItem('foo');
|
|
||||||
$item->isHit();
|
|
||||||
$pool->save($item->set('bar'));
|
|
||||||
$this->assertFalse($isCalled);
|
|
||||||
} finally {
|
|
||||||
restore_error_handler();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,56 +0,0 @@
|
||||||
<?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\Tests\Adapter;
|
|
||||||
|
|
||||||
use Symfony\Component\Cache\Adapter\ArrayAdapter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @group time-sensitive
|
|
||||||
*/
|
|
||||||
class ArrayAdapterTest extends AdapterTestCase
|
|
||||||
{
|
|
||||||
protected $skippedTests = [
|
|
||||||
'testDeferredSaveWithoutCommit' => 'Assumes a shared cache which ArrayAdapter is not.',
|
|
||||||
'testSaveWithoutExpire' => 'Assumes a shared cache which ArrayAdapter is not.',
|
|
||||||
];
|
|
||||||
|
|
||||||
public function createCachePool($defaultLifetime = 0)
|
|
||||||
{
|
|
||||||
return new ArrayAdapter($defaultLifetime);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testGetValuesHitAndMiss()
|
|
||||||
{
|
|
||||||
/** @var ArrayAdapter $cache */
|
|
||||||
$cache = $this->createCachePool();
|
|
||||||
|
|
||||||
// Hit
|
|
||||||
$item = $cache->getItem('foo');
|
|
||||||
$item->set('4711');
|
|
||||||
$cache->save($item);
|
|
||||||
|
|
||||||
$fooItem = $cache->getItem('foo');
|
|
||||||
$this->assertTrue($fooItem->isHit());
|
|
||||||
$this->assertEquals('4711', $fooItem->get());
|
|
||||||
|
|
||||||
// Miss (should be present as NULL in $values)
|
|
||||||
$cache->getItem('bar');
|
|
||||||
|
|
||||||
$values = $cache->getValues();
|
|
||||||
|
|
||||||
$this->assertCount(2, $values);
|
|
||||||
$this->assertArrayHasKey('foo', $values);
|
|
||||||
$this->assertSame(serialize('4711'), $values['foo']);
|
|
||||||
$this->assertArrayHasKey('bar', $values);
|
|
||||||
$this->assertNull($values['bar']);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,233 +0,0 @@
|
||||||
<?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\Tests\Adapter;
|
|
||||||
|
|
||||||
use PHPUnit\Framework\MockObject\MockObject;
|
|
||||||
use Symfony\Component\Cache\Adapter\AdapterInterface;
|
|
||||||
use Symfony\Component\Cache\Adapter\ArrayAdapter;
|
|
||||||
use Symfony\Component\Cache\Adapter\ChainAdapter;
|
|
||||||
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
|
|
||||||
use Symfony\Component\Cache\PruneableInterface;
|
|
||||||
use Symfony\Component\Cache\Tests\Fixtures\ExternalAdapter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
|
||||||
* @group time-sensitive
|
|
||||||
*/
|
|
||||||
class ChainAdapterTest extends AdapterTestCase
|
|
||||||
{
|
|
||||||
public function createCachePool($defaultLifetime = 0)
|
|
||||||
{
|
|
||||||
return new ChainAdapter([new ArrayAdapter($defaultLifetime), new ExternalAdapter($defaultLifetime), new FilesystemAdapter('', $defaultLifetime)], $defaultLifetime);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testEmptyAdaptersException()
|
|
||||||
{
|
|
||||||
$this->expectException('Symfony\Component\Cache\Exception\InvalidArgumentException');
|
|
||||||
$this->expectExceptionMessage('At least one adapter must be specified.');
|
|
||||||
new ChainAdapter([]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testInvalidAdapterException()
|
|
||||||
{
|
|
||||||
$this->expectException('Symfony\Component\Cache\Exception\InvalidArgumentException');
|
|
||||||
$this->expectExceptionMessage('The class "stdClass" does not implement');
|
|
||||||
new ChainAdapter([new \stdClass()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testPrune()
|
|
||||||
{
|
|
||||||
if (isset($this->skippedTests[__FUNCTION__])) {
|
|
||||||
$this->markTestSkipped($this->skippedTests[__FUNCTION__]);
|
|
||||||
}
|
|
||||||
|
|
||||||
$cache = new ChainAdapter([
|
|
||||||
$this->getPruneableMock(),
|
|
||||||
$this->getNonPruneableMock(),
|
|
||||||
$this->getPruneableMock(),
|
|
||||||
]);
|
|
||||||
$this->assertTrue($cache->prune());
|
|
||||||
|
|
||||||
$cache = new ChainAdapter([
|
|
||||||
$this->getPruneableMock(),
|
|
||||||
$this->getFailingPruneableMock(),
|
|
||||||
$this->getPruneableMock(),
|
|
||||||
]);
|
|
||||||
$this->assertFalse($cache->prune());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testMultipleCachesExpirationWhenCommonTtlIsNotSet()
|
|
||||||
{
|
|
||||||
if (isset($this->skippedTests[__FUNCTION__])) {
|
|
||||||
$this->markTestSkipped($this->skippedTests[__FUNCTION__]);
|
|
||||||
}
|
|
||||||
|
|
||||||
$adapter1 = new ArrayAdapter(4);
|
|
||||||
$adapter2 = new ArrayAdapter(2);
|
|
||||||
|
|
||||||
$cache = new ChainAdapter([$adapter1, $adapter2]);
|
|
||||||
|
|
||||||
$cache->save($cache->getItem('key')->set('value'));
|
|
||||||
|
|
||||||
$item = $adapter1->getItem('key');
|
|
||||||
$this->assertTrue($item->isHit());
|
|
||||||
$this->assertEquals('value', $item->get());
|
|
||||||
|
|
||||||
$item = $adapter2->getItem('key');
|
|
||||||
$this->assertTrue($item->isHit());
|
|
||||||
$this->assertEquals('value', $item->get());
|
|
||||||
|
|
||||||
sleep(2);
|
|
||||||
|
|
||||||
$item = $adapter1->getItem('key');
|
|
||||||
$this->assertTrue($item->isHit());
|
|
||||||
$this->assertEquals('value', $item->get());
|
|
||||||
|
|
||||||
$item = $adapter2->getItem('key');
|
|
||||||
$this->assertFalse($item->isHit());
|
|
||||||
|
|
||||||
sleep(2);
|
|
||||||
|
|
||||||
$item = $adapter1->getItem('key');
|
|
||||||
$this->assertFalse($item->isHit());
|
|
||||||
|
|
||||||
$adapter2->save($adapter2->getItem('key1')->set('value1'));
|
|
||||||
|
|
||||||
$item = $cache->getItem('key1');
|
|
||||||
$this->assertTrue($item->isHit());
|
|
||||||
$this->assertEquals('value1', $item->get());
|
|
||||||
|
|
||||||
sleep(2);
|
|
||||||
|
|
||||||
$item = $adapter1->getItem('key1');
|
|
||||||
$this->assertTrue($item->isHit());
|
|
||||||
$this->assertEquals('value1', $item->get());
|
|
||||||
|
|
||||||
$item = $adapter2->getItem('key1');
|
|
||||||
$this->assertFalse($item->isHit());
|
|
||||||
|
|
||||||
sleep(2);
|
|
||||||
|
|
||||||
$item = $adapter1->getItem('key1');
|
|
||||||
$this->assertFalse($item->isHit());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testMultipleCachesExpirationWhenCommonTtlIsSet()
|
|
||||||
{
|
|
||||||
if (isset($this->skippedTests[__FUNCTION__])) {
|
|
||||||
$this->markTestSkipped($this->skippedTests[__FUNCTION__]);
|
|
||||||
}
|
|
||||||
|
|
||||||
$adapter1 = new ArrayAdapter(4);
|
|
||||||
$adapter2 = new ArrayAdapter(2);
|
|
||||||
|
|
||||||
$cache = new ChainAdapter([$adapter1, $adapter2], 6);
|
|
||||||
|
|
||||||
$cache->save($cache->getItem('key')->set('value'));
|
|
||||||
|
|
||||||
$item = $adapter1->getItem('key');
|
|
||||||
$this->assertTrue($item->isHit());
|
|
||||||
$this->assertEquals('value', $item->get());
|
|
||||||
|
|
||||||
$item = $adapter2->getItem('key');
|
|
||||||
$this->assertTrue($item->isHit());
|
|
||||||
$this->assertEquals('value', $item->get());
|
|
||||||
|
|
||||||
sleep(2);
|
|
||||||
|
|
||||||
$item = $adapter1->getItem('key');
|
|
||||||
$this->assertTrue($item->isHit());
|
|
||||||
$this->assertEquals('value', $item->get());
|
|
||||||
|
|
||||||
$item = $adapter2->getItem('key');
|
|
||||||
$this->assertFalse($item->isHit());
|
|
||||||
|
|
||||||
sleep(2);
|
|
||||||
|
|
||||||
$item = $adapter1->getItem('key');
|
|
||||||
$this->assertFalse($item->isHit());
|
|
||||||
|
|
||||||
$adapter2->save($adapter2->getItem('key1')->set('value1'));
|
|
||||||
|
|
||||||
$item = $cache->getItem('key1');
|
|
||||||
$this->assertTrue($item->isHit());
|
|
||||||
$this->assertEquals('value1', $item->get());
|
|
||||||
|
|
||||||
sleep(2);
|
|
||||||
|
|
||||||
$item = $adapter1->getItem('key1');
|
|
||||||
$this->assertTrue($item->isHit());
|
|
||||||
$this->assertEquals('value1', $item->get());
|
|
||||||
|
|
||||||
$item = $adapter2->getItem('key1');
|
|
||||||
$this->assertFalse($item->isHit());
|
|
||||||
|
|
||||||
sleep(2);
|
|
||||||
|
|
||||||
$item = $adapter1->getItem('key1');
|
|
||||||
$this->assertTrue($item->isHit());
|
|
||||||
$this->assertEquals('value1', $item->get());
|
|
||||||
|
|
||||||
sleep(2);
|
|
||||||
|
|
||||||
$item = $adapter1->getItem('key1');
|
|
||||||
$this->assertFalse($item->isHit());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return MockObject|PruneableCacheInterface
|
|
||||||
*/
|
|
||||||
private function getPruneableMock()
|
|
||||||
{
|
|
||||||
$pruneable = $this
|
|
||||||
->getMockBuilder(PruneableCacheInterface::class)
|
|
||||||
->getMock();
|
|
||||||
|
|
||||||
$pruneable
|
|
||||||
->expects($this->atLeastOnce())
|
|
||||||
->method('prune')
|
|
||||||
->willReturn(true);
|
|
||||||
|
|
||||||
return $pruneable;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return MockObject|PruneableCacheInterface
|
|
||||||
*/
|
|
||||||
private function getFailingPruneableMock()
|
|
||||||
{
|
|
||||||
$pruneable = $this
|
|
||||||
->getMockBuilder(PruneableCacheInterface::class)
|
|
||||||
->getMock();
|
|
||||||
|
|
||||||
$pruneable
|
|
||||||
->expects($this->atLeastOnce())
|
|
||||||
->method('prune')
|
|
||||||
->willReturn(false);
|
|
||||||
|
|
||||||
return $pruneable;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return MockObject|AdapterInterface
|
|
||||||
*/
|
|
||||||
private function getNonPruneableMock()
|
|
||||||
{
|
|
||||||
return $this
|
|
||||||
->getMockBuilder(AdapterInterface::class)
|
|
||||||
->getMock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface PruneableCacheInterface extends PruneableInterface, AdapterInterface
|
|
||||||
{
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
<?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\Tests\Adapter;
|
|
||||||
|
|
||||||
use Symfony\Component\Cache\Adapter\DoctrineAdapter;
|
|
||||||
use Symfony\Component\Cache\Tests\Fixtures\ArrayCache;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @group time-sensitive
|
|
||||||
*/
|
|
||||||
class DoctrineAdapterTest extends AdapterTestCase
|
|
||||||
{
|
|
||||||
protected $skippedTests = [
|
|
||||||
'testDeferredSaveWithoutCommit' => 'Assumes a shared cache which ArrayCache is not.',
|
|
||||||
'testSaveWithoutExpire' => 'Assumes a shared cache which ArrayCache is not.',
|
|
||||||
'testNotUnserializable' => 'ArrayCache does not use serialize/unserialize',
|
|
||||||
];
|
|
||||||
|
|
||||||
public function createCachePool($defaultLifetime = 0)
|
|
||||||
{
|
|
||||||
return new DoctrineAdapter(new ArrayCache($defaultLifetime), '', $defaultLifetime);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,61 +0,0 @@
|
||||||
<?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\Tests\Adapter;
|
|
||||||
|
|
||||||
use Psr\Cache\CacheItemPoolInterface;
|
|
||||||
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @group time-sensitive
|
|
||||||
*/
|
|
||||||
class FilesystemAdapterTest extends AdapterTestCase
|
|
||||||
{
|
|
||||||
public function createCachePool($defaultLifetime = 0)
|
|
||||||
{
|
|
||||||
return new FilesystemAdapter('', $defaultLifetime);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function tearDownAfterClass()
|
|
||||||
{
|
|
||||||
self::rmdir(sys_get_temp_dir().'/symfony-cache');
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function rmdir($dir)
|
|
||||||
{
|
|
||||||
if (!file_exists($dir)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!$dir || 0 !== strpos(\dirname($dir), sys_get_temp_dir())) {
|
|
||||||
throw new \Exception(__METHOD__."() operates only on subdirs of system's temp dir");
|
|
||||||
}
|
|
||||||
$children = new \RecursiveIteratorIterator(
|
|
||||||
new \RecursiveDirectoryIterator($dir, \RecursiveDirectoryIterator::SKIP_DOTS),
|
|
||||||
\RecursiveIteratorIterator::CHILD_FIRST
|
|
||||||
);
|
|
||||||
foreach ($children as $child) {
|
|
||||||
if ($child->isDir()) {
|
|
||||||
rmdir($child);
|
|
||||||
} else {
|
|
||||||
unlink($child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rmdir($dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function isPruned(CacheItemPoolInterface $cache, $name)
|
|
||||||
{
|
|
||||||
$getFileMethod = (new \ReflectionObject($cache))->getMethod('getFile');
|
|
||||||
$getFileMethod->setAccessible(true);
|
|
||||||
|
|
||||||
return !file_exists($getFileMethod->invoke($cache, $name));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,87 +0,0 @@
|
||||||
<?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\Tests\Adapter;
|
|
||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
|
||||||
use Symfony\Component\Cache\Adapter\AbstractAdapter;
|
|
||||||
|
|
||||||
class MaxIdLengthAdapterTest extends TestCase
|
|
||||||
{
|
|
||||||
public function testLongKey()
|
|
||||||
{
|
|
||||||
$cache = $this->getMockBuilder(MaxIdLengthAdapter::class)
|
|
||||||
->setConstructorArgs([str_repeat('-', 10)])
|
|
||||||
->setMethods(['doHave', 'doFetch', 'doDelete', 'doSave', 'doClear'])
|
|
||||||
->getMock();
|
|
||||||
|
|
||||||
$cache->expects($this->exactly(2))
|
|
||||||
->method('doHave')
|
|
||||||
->withConsecutive(
|
|
||||||
[$this->equalTo('----------:0GTYWa9n4ed8vqNlOT2iEr:')],
|
|
||||||
[$this->equalTo('----------:---------------------------------------')]
|
|
||||||
);
|
|
||||||
|
|
||||||
$cache->hasItem(str_repeat('-', 40));
|
|
||||||
$cache->hasItem(str_repeat('-', 39));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testLongKeyVersioning()
|
|
||||||
{
|
|
||||||
$cache = $this->getMockBuilder(MaxIdLengthAdapter::class)
|
|
||||||
->setConstructorArgs([str_repeat('-', 26)])
|
|
||||||
->getMock();
|
|
||||||
|
|
||||||
$cache
|
|
||||||
->method('doFetch')
|
|
||||||
->willReturn(['2:']);
|
|
||||||
|
|
||||||
$reflectionClass = new \ReflectionClass(AbstractAdapter::class);
|
|
||||||
|
|
||||||
$reflectionMethod = $reflectionClass->getMethod('getId');
|
|
||||||
$reflectionMethod->setAccessible(true);
|
|
||||||
|
|
||||||
// No versioning enabled
|
|
||||||
$this->assertEquals('--------------------------:------------', $reflectionMethod->invokeArgs($cache, [str_repeat('-', 12)]));
|
|
||||||
$this->assertLessThanOrEqual(50, \strlen($reflectionMethod->invokeArgs($cache, [str_repeat('-', 12)])));
|
|
||||||
$this->assertLessThanOrEqual(50, \strlen($reflectionMethod->invokeArgs($cache, [str_repeat('-', 23)])));
|
|
||||||
$this->assertLessThanOrEqual(50, \strlen($reflectionMethod->invokeArgs($cache, [str_repeat('-', 40)])));
|
|
||||||
|
|
||||||
$reflectionProperty = $reflectionClass->getProperty('versioningIsEnabled');
|
|
||||||
$reflectionProperty->setAccessible(true);
|
|
||||||
$reflectionProperty->setValue($cache, true);
|
|
||||||
|
|
||||||
// Versioning enabled
|
|
||||||
$this->assertEquals('--------------------------:2:------------', $reflectionMethod->invokeArgs($cache, [str_repeat('-', 12)]));
|
|
||||||
$this->assertLessThanOrEqual(50, \strlen($reflectionMethod->invokeArgs($cache, [str_repeat('-', 12)])));
|
|
||||||
$this->assertLessThanOrEqual(50, \strlen($reflectionMethod->invokeArgs($cache, [str_repeat('-', 23)])));
|
|
||||||
$this->assertLessThanOrEqual(50, \strlen($reflectionMethod->invokeArgs($cache, [str_repeat('-', 40)])));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testTooLongNamespace()
|
|
||||||
{
|
|
||||||
$this->expectException('Symfony\Component\Cache\Exception\InvalidArgumentException');
|
|
||||||
$this->expectExceptionMessage('Namespace must be 26 chars max, 40 given ("----------------------------------------")');
|
|
||||||
$this->getMockBuilder(MaxIdLengthAdapter::class)
|
|
||||||
->setConstructorArgs([str_repeat('-', 40)])
|
|
||||||
->getMock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class MaxIdLengthAdapter extends AbstractAdapter
|
|
||||||
{
|
|
||||||
protected $maxIdLength = 50;
|
|
||||||
|
|
||||||
public function __construct($ns)
|
|
||||||
{
|
|
||||||
parent::__construct($ns);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,204 +0,0 @@
|
||||||
<?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\Tests\Adapter;
|
|
||||||
|
|
||||||
use Symfony\Component\Cache\Adapter\AbstractAdapter;
|
|
||||||
use Symfony\Component\Cache\Adapter\MemcachedAdapter;
|
|
||||||
|
|
||||||
class MemcachedAdapterTest extends AdapterTestCase
|
|
||||||
{
|
|
||||||
protected $skippedTests = [
|
|
||||||
'testHasItemReturnsFalseWhenDeferredItemIsExpired' => 'Testing expiration slows down the test suite',
|
|
||||||
'testDefaultLifeTime' => 'Testing expiration slows down the test suite',
|
|
||||||
];
|
|
||||||
|
|
||||||
protected static $client;
|
|
||||||
|
|
||||||
public static function setUpBeforeClass()
|
|
||||||
{
|
|
||||||
if (!MemcachedAdapter::isSupported()) {
|
|
||||||
self::markTestSkipped('Extension memcached >=2.2.0 required.');
|
|
||||||
}
|
|
||||||
self::$client = AbstractAdapter::createConnection('memcached://'.getenv('MEMCACHED_HOST'), ['binary_protocol' => false]);
|
|
||||||
self::$client->get('foo');
|
|
||||||
$code = self::$client->getResultCode();
|
|
||||||
|
|
||||||
if (\Memcached::RES_SUCCESS !== $code && \Memcached::RES_NOTFOUND !== $code) {
|
|
||||||
self::markTestSkipped('Memcached error: '.strtolower(self::$client->getResultMessage()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function createCachePool($defaultLifetime = 0)
|
|
||||||
{
|
|
||||||
$client = $defaultLifetime ? AbstractAdapter::createConnection('memcached://'.getenv('MEMCACHED_HOST')) : self::$client;
|
|
||||||
|
|
||||||
return new MemcachedAdapter($client, str_replace('\\', '.', __CLASS__), $defaultLifetime);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testOptions()
|
|
||||||
{
|
|
||||||
$client = MemcachedAdapter::createConnection([], [
|
|
||||||
'libketama_compatible' => false,
|
|
||||||
'distribution' => 'modula',
|
|
||||||
'compression' => true,
|
|
||||||
'serializer' => 'php',
|
|
||||||
'hash' => 'md5',
|
|
||||||
]);
|
|
||||||
|
|
||||||
$this->assertSame(\Memcached::SERIALIZER_PHP, $client->getOption(\Memcached::OPT_SERIALIZER));
|
|
||||||
$this->assertSame(\Memcached::HASH_MD5, $client->getOption(\Memcached::OPT_HASH));
|
|
||||||
$this->assertTrue($client->getOption(\Memcached::OPT_COMPRESSION));
|
|
||||||
$this->assertSame(0, $client->getOption(\Memcached::OPT_LIBKETAMA_COMPATIBLE));
|
|
||||||
$this->assertSame(\Memcached::DISTRIBUTION_MODULA, $client->getOption(\Memcached::OPT_DISTRIBUTION));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @dataProvider provideBadOptions
|
|
||||||
*/
|
|
||||||
public function testBadOptions($name, $value)
|
|
||||||
{
|
|
||||||
if (\PHP_VERSION_ID < 80000) {
|
|
||||||
$this->expectException('ErrorException');
|
|
||||||
$this->expectExceptionMessage('constant(): Couldn\'t find constant Memcached::');
|
|
||||||
} else {
|
|
||||||
$this->expectException('Error');
|
|
||||||
$this->expectExceptionMessage('Undefined constant Memcached::');
|
|
||||||
}
|
|
||||||
|
|
||||||
MemcachedAdapter::createConnection([], [$name => $value]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function provideBadOptions()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
['foo', 'bar'],
|
|
||||||
['hash', 'zyx'],
|
|
||||||
['serializer', 'zyx'],
|
|
||||||
['distribution', 'zyx'],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testDefaultOptions()
|
|
||||||
{
|
|
||||||
$this->assertTrue(MemcachedAdapter::isSupported());
|
|
||||||
|
|
||||||
$client = MemcachedAdapter::createConnection([]);
|
|
||||||
|
|
||||||
$this->assertTrue($client->getOption(\Memcached::OPT_COMPRESSION));
|
|
||||||
$this->assertSame(1, $client->getOption(\Memcached::OPT_BINARY_PROTOCOL));
|
|
||||||
$this->assertSame(1, $client->getOption(\Memcached::OPT_TCP_NODELAY));
|
|
||||||
$this->assertSame(1, $client->getOption(\Memcached::OPT_LIBKETAMA_COMPATIBLE));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testOptionSerializer()
|
|
||||||
{
|
|
||||||
$this->expectException('Symfony\Component\Cache\Exception\CacheException');
|
|
||||||
$this->expectExceptionMessage('MemcachedAdapter: "serializer" option must be "php" or "igbinary".');
|
|
||||||
if (!\Memcached::HAVE_JSON) {
|
|
||||||
$this->markTestSkipped('Memcached::HAVE_JSON required');
|
|
||||||
}
|
|
||||||
|
|
||||||
new MemcachedAdapter(MemcachedAdapter::createConnection([], ['serializer' => 'json']));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @dataProvider provideServersSetting
|
|
||||||
*/
|
|
||||||
public function testServersSetting($dsn, $host, $port)
|
|
||||||
{
|
|
||||||
$client1 = MemcachedAdapter::createConnection($dsn);
|
|
||||||
$client2 = MemcachedAdapter::createConnection([$dsn]);
|
|
||||||
$client3 = MemcachedAdapter::createConnection([[$host, $port]]);
|
|
||||||
$expect = [
|
|
||||||
'host' => $host,
|
|
||||||
'port' => $port,
|
|
||||||
];
|
|
||||||
|
|
||||||
$f = function ($s) { return ['host' => $s['host'], 'port' => $s['port']]; };
|
|
||||||
$this->assertSame([$expect], array_map($f, $client1->getServerList()));
|
|
||||||
$this->assertSame([$expect], array_map($f, $client2->getServerList()));
|
|
||||||
$this->assertSame([$expect], array_map($f, $client3->getServerList()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function provideServersSetting()
|
|
||||||
{
|
|
||||||
yield [
|
|
||||||
'memcached://127.0.0.1/50',
|
|
||||||
'127.0.0.1',
|
|
||||||
11211,
|
|
||||||
];
|
|
||||||
yield [
|
|
||||||
'memcached://localhost:11222?weight=25',
|
|
||||||
'localhost',
|
|
||||||
11222,
|
|
||||||
];
|
|
||||||
if (filter_var(ini_get('memcached.use_sasl'), \FILTER_VALIDATE_BOOLEAN)) {
|
|
||||||
yield [
|
|
||||||
'memcached://user:password@127.0.0.1?weight=50',
|
|
||||||
'127.0.0.1',
|
|
||||||
11211,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
yield [
|
|
||||||
'memcached:///var/run/memcached.sock?weight=25',
|
|
||||||
'/var/run/memcached.sock',
|
|
||||||
0,
|
|
||||||
];
|
|
||||||
yield [
|
|
||||||
'memcached:///var/local/run/memcached.socket?weight=25',
|
|
||||||
'/var/local/run/memcached.socket',
|
|
||||||
0,
|
|
||||||
];
|
|
||||||
if (filter_var(ini_get('memcached.use_sasl'), \FILTER_VALIDATE_BOOLEAN)) {
|
|
||||||
yield [
|
|
||||||
'memcached://user:password@/var/local/run/memcached.socket?weight=25',
|
|
||||||
'/var/local/run/memcached.socket',
|
|
||||||
0,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @dataProvider provideDsnWithOptions
|
|
||||||
*/
|
|
||||||
public function testDsnWithOptions($dsn, array $options, array $expectedOptions)
|
|
||||||
{
|
|
||||||
$client = MemcachedAdapter::createConnection($dsn, $options);
|
|
||||||
|
|
||||||
foreach ($expectedOptions as $option => $expect) {
|
|
||||||
$this->assertSame($expect, $client->getOption($option));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function provideDsnWithOptions()
|
|
||||||
{
|
|
||||||
if (!class_exists('\Memcached')) {
|
|
||||||
self::markTestSkipped('Extension memcached required.');
|
|
||||||
}
|
|
||||||
|
|
||||||
yield [
|
|
||||||
'memcached://localhost:11222?retry_timeout=10',
|
|
||||||
[\Memcached::OPT_RETRY_TIMEOUT => 8],
|
|
||||||
[\Memcached::OPT_RETRY_TIMEOUT => 10],
|
|
||||||
];
|
|
||||||
yield [
|
|
||||||
'memcached://localhost:11222?socket_recv_size=1&socket_send_size=2',
|
|
||||||
[\Memcached::OPT_RETRY_TIMEOUT => 8],
|
|
||||||
[\Memcached::OPT_SOCKET_RECV_SIZE => 1, \Memcached::OPT_SOCKET_SEND_SIZE => 2, \Memcached::OPT_RETRY_TIMEOUT => 8],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testClear()
|
|
||||||
{
|
|
||||||
$this->assertTrue($this->createCachePool()->clear());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
<?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\Tests\Adapter;
|
|
||||||
|
|
||||||
use Symfony\Component\Cache\Adapter\ArrayAdapter;
|
|
||||||
use Symfony\Component\Cache\Adapter\ProxyAdapter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @group time-sensitive
|
|
||||||
*/
|
|
||||||
class NamespacedProxyAdapterTest extends ProxyAdapterTest
|
|
||||||
{
|
|
||||||
public function createCachePool($defaultLifetime = 0)
|
|
||||||
{
|
|
||||||
return new ProxyAdapter(new ArrayAdapter($defaultLifetime), 'foo', $defaultLifetime);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,128 +0,0 @@
|
||||||
<?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\Tests\Adapter;
|
|
||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
|
||||||
use Psr\Cache\CacheItemInterface;
|
|
||||||
use Symfony\Component\Cache\Adapter\NullAdapter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @group time-sensitive
|
|
||||||
*/
|
|
||||||
class NullAdapterTest extends TestCase
|
|
||||||
{
|
|
||||||
public function createCachePool()
|
|
||||||
{
|
|
||||||
return new NullAdapter();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testGetItem()
|
|
||||||
{
|
|
||||||
$adapter = $this->createCachePool();
|
|
||||||
|
|
||||||
$item = $adapter->getItem('key');
|
|
||||||
$this->assertFalse($item->isHit());
|
|
||||||
$this->assertNull($item->get(), "Item's value must be null when isHit is false.");
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testHasItem()
|
|
||||||
{
|
|
||||||
$this->assertFalse($this->createCachePool()->hasItem('key'));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testGetItems()
|
|
||||||
{
|
|
||||||
$adapter = $this->createCachePool();
|
|
||||||
|
|
||||||
$keys = ['foo', 'bar', 'baz', 'biz'];
|
|
||||||
|
|
||||||
/** @var CacheItemInterface[] $items */
|
|
||||||
$items = $adapter->getItems($keys);
|
|
||||||
$count = 0;
|
|
||||||
|
|
||||||
foreach ($items as $key => $item) {
|
|
||||||
$itemKey = $item->getKey();
|
|
||||||
|
|
||||||
$this->assertEquals($itemKey, $key, 'Keys must be preserved when fetching multiple items');
|
|
||||||
$this->assertContains($key, $keys, 'Cache key can not change.');
|
|
||||||
$this->assertFalse($item->isHit());
|
|
||||||
|
|
||||||
// Remove $key for $keys
|
|
||||||
foreach ($keys as $k => $v) {
|
|
||||||
if ($v === $key) {
|
|
||||||
unset($keys[$k]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
++$count;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->assertSame(4, $count);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testIsHit()
|
|
||||||
{
|
|
||||||
$adapter = $this->createCachePool();
|
|
||||||
|
|
||||||
$item = $adapter->getItem('key');
|
|
||||||
$this->assertFalse($item->isHit());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testClear()
|
|
||||||
{
|
|
||||||
$this->assertTrue($this->createCachePool()->clear());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testDeleteItem()
|
|
||||||
{
|
|
||||||
$this->assertTrue($this->createCachePool()->deleteItem('key'));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testDeleteItems()
|
|
||||||
{
|
|
||||||
$this->assertTrue($this->createCachePool()->deleteItems(['key', 'foo', 'bar']));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testSave()
|
|
||||||
{
|
|
||||||
$adapter = $this->createCachePool();
|
|
||||||
|
|
||||||
$item = $adapter->getItem('key');
|
|
||||||
$this->assertFalse($item->isHit());
|
|
||||||
$this->assertNull($item->get(), "Item's value must be null when isHit is false.");
|
|
||||||
|
|
||||||
$this->assertFalse($adapter->save($item));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testDeferredSave()
|
|
||||||
{
|
|
||||||
$adapter = $this->createCachePool();
|
|
||||||
|
|
||||||
$item = $adapter->getItem('key');
|
|
||||||
$this->assertFalse($item->isHit());
|
|
||||||
$this->assertNull($item->get(), "Item's value must be null when isHit is false.");
|
|
||||||
|
|
||||||
$this->assertFalse($adapter->saveDeferred($item));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testCommit()
|
|
||||||
{
|
|
||||||
$adapter = $this->createCachePool();
|
|
||||||
|
|
||||||
$item = $adapter->getItem('key');
|
|
||||||
$this->assertFalse($item->isHit());
|
|
||||||
$this->assertNull($item->get(), "Item's value must be null when isHit is false.");
|
|
||||||
|
|
||||||
$this->assertFalse($adapter->saveDeferred($item));
|
|
||||||
$this->assertFalse($this->createCachePool()->commit());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,73 +0,0 @@
|
||||||
<?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\Tests\Adapter;
|
|
||||||
|
|
||||||
use Symfony\Component\Cache\Adapter\PdoAdapter;
|
|
||||||
use Symfony\Component\Cache\Tests\Traits\PdoPruneableTrait;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @group time-sensitive
|
|
||||||
*/
|
|
||||||
class PdoAdapterTest extends AdapterTestCase
|
|
||||||
{
|
|
||||||
use PdoPruneableTrait;
|
|
||||||
|
|
||||||
protected static $dbFile;
|
|
||||||
|
|
||||||
public static function setUpBeforeClass()
|
|
||||||
{
|
|
||||||
if (!\extension_loaded('pdo_sqlite')) {
|
|
||||||
self::markTestSkipped('Extension pdo_sqlite required.');
|
|
||||||
}
|
|
||||||
|
|
||||||
self::$dbFile = tempnam(sys_get_temp_dir(), 'sf_sqlite_cache');
|
|
||||||
|
|
||||||
$pool = new PdoAdapter('sqlite:'.self::$dbFile);
|
|
||||||
$pool->createTable();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function tearDownAfterClass()
|
|
||||||
{
|
|
||||||
@unlink(self::$dbFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function createCachePool($defaultLifetime = 0)
|
|
||||||
{
|
|
||||||
return new PdoAdapter('sqlite:'.self::$dbFile, 'ns', $defaultLifetime);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testCleanupExpiredItems()
|
|
||||||
{
|
|
||||||
$pdo = new \PDO('sqlite:'.self::$dbFile);
|
|
||||||
|
|
||||||
$getCacheItemCount = function () use ($pdo) {
|
|
||||||
return (int) $pdo->query('SELECT COUNT(*) FROM cache_items')->fetch(\PDO::FETCH_COLUMN);
|
|
||||||
};
|
|
||||||
|
|
||||||
$this->assertSame(0, $getCacheItemCount());
|
|
||||||
|
|
||||||
$cache = $this->createCachePool();
|
|
||||||
|
|
||||||
$item = $cache->getItem('some_nice_key');
|
|
||||||
$item->expiresAfter(1);
|
|
||||||
$item->set(1);
|
|
||||||
|
|
||||||
$cache->save($item);
|
|
||||||
$this->assertSame(1, $getCacheItemCount());
|
|
||||||
|
|
||||||
sleep(2);
|
|
||||||
|
|
||||||
$newItem = $cache->getItem($item->getKey());
|
|
||||||
$this->assertFalse($newItem->isHit());
|
|
||||||
$this->assertSame(0, $getCacheItemCount(), 'PDOAdapter must clean up expired items');
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,48 +0,0 @@
|
||||||
<?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\Tests\Adapter;
|
|
||||||
|
|
||||||
use Doctrine\DBAL\DriverManager;
|
|
||||||
use Symfony\Component\Cache\Adapter\PdoAdapter;
|
|
||||||
use Symfony\Component\Cache\Tests\Traits\PdoPruneableTrait;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @group time-sensitive
|
|
||||||
*/
|
|
||||||
class PdoDbalAdapterTest extends AdapterTestCase
|
|
||||||
{
|
|
||||||
use PdoPruneableTrait;
|
|
||||||
|
|
||||||
protected static $dbFile;
|
|
||||||
|
|
||||||
public static function setUpBeforeClass()
|
|
||||||
{
|
|
||||||
if (!\extension_loaded('pdo_sqlite')) {
|
|
||||||
self::markTestSkipped('Extension pdo_sqlite required.');
|
|
||||||
}
|
|
||||||
|
|
||||||
self::$dbFile = tempnam(sys_get_temp_dir(), 'sf_sqlite_cache');
|
|
||||||
|
|
||||||
$pool = new PdoAdapter(DriverManager::getConnection(['driver' => 'pdo_sqlite', 'path' => self::$dbFile]));
|
|
||||||
$pool->createTable();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function tearDownAfterClass()
|
|
||||||
{
|
|
||||||
@unlink(self::$dbFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function createCachePool($defaultLifetime = 0)
|
|
||||||
{
|
|
||||||
return new PdoAdapter(DriverManager::getConnection(['driver' => 'pdo_sqlite', 'path' => self::$dbFile]), '', $defaultLifetime);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,135 +0,0 @@
|
||||||
<?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\Tests\Adapter;
|
|
||||||
|
|
||||||
use Psr\Cache\CacheItemInterface;
|
|
||||||
use Symfony\Component\Cache\Adapter\NullAdapter;
|
|
||||||
use Symfony\Component\Cache\Adapter\PhpArrayAdapter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @group time-sensitive
|
|
||||||
*/
|
|
||||||
class PhpArrayAdapterTest extends AdapterTestCase
|
|
||||||
{
|
|
||||||
protected $skippedTests = [
|
|
||||||
'testBasicUsage' => 'PhpArrayAdapter is read-only.',
|
|
||||||
'testBasicUsageWithLongKey' => 'PhpArrayAdapter is read-only.',
|
|
||||||
'testClear' => 'PhpArrayAdapter is read-only.',
|
|
||||||
'testClearWithDeferredItems' => 'PhpArrayAdapter is read-only.',
|
|
||||||
'testDeleteItem' => 'PhpArrayAdapter is read-only.',
|
|
||||||
'testSaveExpired' => 'PhpArrayAdapter is read-only.',
|
|
||||||
'testSaveWithoutExpire' => 'PhpArrayAdapter is read-only.',
|
|
||||||
'testDeferredSave' => 'PhpArrayAdapter is read-only.',
|
|
||||||
'testDeferredSaveWithoutCommit' => 'PhpArrayAdapter is read-only.',
|
|
||||||
'testDeleteItems' => 'PhpArrayAdapter is read-only.',
|
|
||||||
'testDeleteDeferredItem' => 'PhpArrayAdapter is read-only.',
|
|
||||||
'testCommit' => 'PhpArrayAdapter is read-only.',
|
|
||||||
'testSaveDeferredWhenChangingValues' => 'PhpArrayAdapter is read-only.',
|
|
||||||
'testSaveDeferredOverwrite' => 'PhpArrayAdapter is read-only.',
|
|
||||||
'testIsHitDeferred' => 'PhpArrayAdapter is read-only.',
|
|
||||||
|
|
||||||
'testExpiresAt' => 'PhpArrayAdapter does not support expiration.',
|
|
||||||
'testExpiresAtWithNull' => 'PhpArrayAdapter does not support expiration.',
|
|
||||||
'testExpiresAfterWithNull' => 'PhpArrayAdapter does not support expiration.',
|
|
||||||
'testDeferredExpired' => 'PhpArrayAdapter does not support expiration.',
|
|
||||||
'testExpiration' => 'PhpArrayAdapter does not support expiration.',
|
|
||||||
|
|
||||||
'testGetItemInvalidKeys' => 'PhpArrayAdapter does not throw exceptions on invalid key.',
|
|
||||||
'testGetItemsInvalidKeys' => 'PhpArrayAdapter does not throw exceptions on invalid key.',
|
|
||||||
'testHasItemInvalidKeys' => 'PhpArrayAdapter does not throw exceptions on invalid key.',
|
|
||||||
'testDeleteItemInvalidKeys' => 'PhpArrayAdapter does not throw exceptions on invalid key.',
|
|
||||||
'testDeleteItemsInvalidKeys' => 'PhpArrayAdapter does not throw exceptions on invalid key.',
|
|
||||||
|
|
||||||
'testDefaultLifeTime' => 'PhpArrayAdapter does not allow configuring a default lifetime.',
|
|
||||||
'testPrune' => 'PhpArrayAdapter just proxies',
|
|
||||||
];
|
|
||||||
|
|
||||||
protected static $file;
|
|
||||||
|
|
||||||
public static function setUpBeforeClass()
|
|
||||||
{
|
|
||||||
self::$file = sys_get_temp_dir().'/symfony-cache/php-array-adapter-test.php';
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function tearDown()
|
|
||||||
{
|
|
||||||
$this->createCachePool()->clear();
|
|
||||||
|
|
||||||
if (file_exists(sys_get_temp_dir().'/symfony-cache')) {
|
|
||||||
FilesystemAdapterTest::rmdir(sys_get_temp_dir().'/symfony-cache');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function createCachePool()
|
|
||||||
{
|
|
||||||
return new PhpArrayAdapterWrapper(self::$file, new NullAdapter());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testStore()
|
|
||||||
{
|
|
||||||
$arrayWithRefs = [];
|
|
||||||
$arrayWithRefs[0] = 123;
|
|
||||||
$arrayWithRefs[1] = &$arrayWithRefs[0];
|
|
||||||
|
|
||||||
$object = (object) [
|
|
||||||
'foo' => 'bar',
|
|
||||||
'foo2' => 'bar2',
|
|
||||||
];
|
|
||||||
|
|
||||||
$expected = [
|
|
||||||
'null' => null,
|
|
||||||
'serializedString' => serialize($object),
|
|
||||||
'arrayWithRefs' => $arrayWithRefs,
|
|
||||||
'object' => $object,
|
|
||||||
'arrayWithObject' => ['bar' => $object],
|
|
||||||
];
|
|
||||||
|
|
||||||
$adapter = $this->createCachePool();
|
|
||||||
$adapter->warmUp($expected);
|
|
||||||
|
|
||||||
foreach ($expected as $key => $value) {
|
|
||||||
$this->assertSame(serialize($value), serialize($adapter->getItem($key)->get()), 'Warm up should create a PHP file that OPCache can load in memory');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testStoredFile()
|
|
||||||
{
|
|
||||||
$expected = [
|
|
||||||
'integer' => 42,
|
|
||||||
'float' => 42.42,
|
|
||||||
'boolean' => true,
|
|
||||||
'array_simple' => ['foo', 'bar'],
|
|
||||||
'array_associative' => ['foo' => 'bar', 'foo2' => 'bar2'],
|
|
||||||
];
|
|
||||||
|
|
||||||
$adapter = $this->createCachePool();
|
|
||||||
$adapter->warmUp($expected);
|
|
||||||
|
|
||||||
$values = eval(substr(file_get_contents(self::$file), 6));
|
|
||||||
|
|
||||||
$this->assertSame($expected, $values, 'Warm up should create a PHP file that OPCache can load in memory');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class PhpArrayAdapterWrapper extends PhpArrayAdapter
|
|
||||||
{
|
|
||||||
public function save(CacheItemInterface $item)
|
|
||||||
{
|
|
||||||
\call_user_func(\Closure::bind(function () use ($item) {
|
|
||||||
$this->values[$item->getKey()] = $item->get();
|
|
||||||
$this->warmUp($this->values);
|
|
||||||
$this->values = eval(substr(file_get_contents($this->file), 6));
|
|
||||||
}, $this, PhpArrayAdapter::class));
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,51 +0,0 @@
|
||||||
<?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\Tests\Adapter;
|
|
||||||
|
|
||||||
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
|
|
||||||
use Symfony\Component\Cache\Adapter\PhpArrayAdapter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @group time-sensitive
|
|
||||||
*/
|
|
||||||
class PhpArrayAdapterWithFallbackTest extends AdapterTestCase
|
|
||||||
{
|
|
||||||
protected $skippedTests = [
|
|
||||||
'testGetItemInvalidKeys' => 'PhpArrayAdapter does not throw exceptions on invalid key.',
|
|
||||||
'testGetItemsInvalidKeys' => 'PhpArrayAdapter does not throw exceptions on invalid key.',
|
|
||||||
'testHasItemInvalidKeys' => 'PhpArrayAdapter does not throw exceptions on invalid key.',
|
|
||||||
'testDeleteItemInvalidKeys' => 'PhpArrayAdapter does not throw exceptions on invalid key.',
|
|
||||||
'testDeleteItemsInvalidKeys' => 'PhpArrayAdapter does not throw exceptions on invalid key.',
|
|
||||||
'testPrune' => 'PhpArrayAdapter just proxies',
|
|
||||||
];
|
|
||||||
|
|
||||||
protected static $file;
|
|
||||||
|
|
||||||
public static function setUpBeforeClass()
|
|
||||||
{
|
|
||||||
self::$file = sys_get_temp_dir().'/symfony-cache/php-array-adapter-test.php';
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function tearDown()
|
|
||||||
{
|
|
||||||
$this->createCachePool()->clear();
|
|
||||||
|
|
||||||
if (file_exists(sys_get_temp_dir().'/symfony-cache')) {
|
|
||||||
FilesystemAdapterTest::rmdir(sys_get_temp_dir().'/symfony-cache');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function createCachePool($defaultLifetime = 0)
|
|
||||||
{
|
|
||||||
return new PhpArrayAdapter(self::$file, new FilesystemAdapter('php-array-fallback', $defaultLifetime));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,47 +0,0 @@
|
||||||
<?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\Tests\Adapter;
|
|
||||||
|
|
||||||
use Psr\Cache\CacheItemPoolInterface;
|
|
||||||
use Symfony\Component\Cache\Adapter\PhpFilesAdapter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @group time-sensitive
|
|
||||||
*/
|
|
||||||
class PhpFilesAdapterTest extends AdapterTestCase
|
|
||||||
{
|
|
||||||
protected $skippedTests = [
|
|
||||||
'testDefaultLifeTime' => 'PhpFilesAdapter does not allow configuring a default lifetime.',
|
|
||||||
];
|
|
||||||
|
|
||||||
public function createCachePool()
|
|
||||||
{
|
|
||||||
if (!PhpFilesAdapter::isSupported()) {
|
|
||||||
$this->markTestSkipped('OPcache extension is not enabled.');
|
|
||||||
}
|
|
||||||
|
|
||||||
return new PhpFilesAdapter('sf-cache');
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function tearDownAfterClass()
|
|
||||||
{
|
|
||||||
FilesystemAdapterTest::rmdir(sys_get_temp_dir().'/symfony-cache');
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function isPruned(CacheItemPoolInterface $cache, $name)
|
|
||||||
{
|
|
||||||
$getFileMethod = (new \ReflectionObject($cache))->getMethod('getFile');
|
|
||||||
$getFileMethod->setAccessible(true);
|
|
||||||
|
|
||||||
return !file_exists($getFileMethod->invoke($cache, $name));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,53 +0,0 @@
|
||||||
<?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\Tests\Adapter;
|
|
||||||
|
|
||||||
use Predis\Connection\StreamConnection;
|
|
||||||
use Symfony\Component\Cache\Adapter\RedisAdapter;
|
|
||||||
|
|
||||||
class PredisAdapterTest extends AbstractRedisAdapterTest
|
|
||||||
{
|
|
||||||
public static function setUpBeforeClass()
|
|
||||||
{
|
|
||||||
parent::setUpBeforeClass();
|
|
||||||
self::$redis = new \Predis\Client(['host' => getenv('REDIS_HOST')]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testCreateConnection()
|
|
||||||
{
|
|
||||||
$redisHost = getenv('REDIS_HOST');
|
|
||||||
|
|
||||||
$redis = RedisAdapter::createConnection('redis://'.$redisHost.'/1', ['class' => \Predis\Client::class, 'timeout' => 3]);
|
|
||||||
$this->assertInstanceOf(\Predis\Client::class, $redis);
|
|
||||||
|
|
||||||
$connection = $redis->getConnection();
|
|
||||||
$this->assertInstanceOf(StreamConnection::class, $connection);
|
|
||||||
|
|
||||||
$params = [
|
|
||||||
'scheme' => 'tcp',
|
|
||||||
'host' => $redisHost,
|
|
||||||
'path' => '',
|
|
||||||
'dbindex' => '1',
|
|
||||||
'port' => 6379,
|
|
||||||
'class' => 'Predis\Client',
|
|
||||||
'timeout' => 3,
|
|
||||||
'persistent' => 0,
|
|
||||||
'persistent_id' => null,
|
|
||||||
'read_timeout' => 0,
|
|
||||||
'retry_interval' => 0,
|
|
||||||
'lazy' => false,
|
|
||||||
'database' => '1',
|
|
||||||
'password' => null,
|
|
||||||
];
|
|
||||||
$this->assertSame($params, $connection->getParameters()->toArray());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
<?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\Tests\Adapter;
|
|
||||||
|
|
||||||
class PredisClusterAdapterTest extends AbstractRedisAdapterTest
|
|
||||||
{
|
|
||||||
public static function setUpBeforeClass()
|
|
||||||
{
|
|
||||||
parent::setUpBeforeClass();
|
|
||||||
self::$redis = new \Predis\Client([['host' => getenv('REDIS_HOST')]]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function tearDownAfterClass()
|
|
||||||
{
|
|
||||||
self::$redis = null;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
<?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\Tests\Adapter;
|
|
||||||
|
|
||||||
class PredisRedisClusterAdapterTest extends AbstractRedisAdapterTest
|
|
||||||
{
|
|
||||||
public static function setUpBeforeClass()
|
|
||||||
{
|
|
||||||
if (!$hosts = getenv('REDIS_CLUSTER_HOSTS')) {
|
|
||||||
self::markTestSkipped('REDIS_CLUSTER_HOSTS env var is not defined.');
|
|
||||||
}
|
|
||||||
self::$redis = new \Predis\Client(explode(' ', $hosts), ['cluster' => 'redis']);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function tearDownAfterClass()
|
|
||||||
{
|
|
||||||
self::$redis = null;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,69 +0,0 @@
|
||||||
<?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\Tests\Adapter;
|
|
||||||
|
|
||||||
use Psr\Cache\CacheItemInterface;
|
|
||||||
use Symfony\Component\Cache\Adapter\ArrayAdapter;
|
|
||||||
use Symfony\Component\Cache\Adapter\ProxyAdapter;
|
|
||||||
use Symfony\Component\Cache\CacheItem;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @group time-sensitive
|
|
||||||
*/
|
|
||||||
class ProxyAdapterTest extends AdapterTestCase
|
|
||||||
{
|
|
||||||
protected $skippedTests = [
|
|
||||||
'testDeferredSaveWithoutCommit' => 'Assumes a shared cache which ArrayAdapter is not.',
|
|
||||||
'testSaveWithoutExpire' => 'Assumes a shared cache which ArrayAdapter is not.',
|
|
||||||
'testPrune' => 'ProxyAdapter just proxies',
|
|
||||||
];
|
|
||||||
|
|
||||||
public function createCachePool($defaultLifetime = 0)
|
|
||||||
{
|
|
||||||
return new ProxyAdapter(new ArrayAdapter(), '', $defaultLifetime);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testProxyfiedItem()
|
|
||||||
{
|
|
||||||
$this->expectException('Exception');
|
|
||||||
$this->expectExceptionMessage('OK bar');
|
|
||||||
$item = new CacheItem();
|
|
||||||
$pool = new ProxyAdapter(new TestingArrayAdapter($item));
|
|
||||||
|
|
||||||
$proxyItem = $pool->getItem('foo');
|
|
||||||
|
|
||||||
$this->assertNotSame($item, $proxyItem);
|
|
||||||
$pool->save($proxyItem->set('bar'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class TestingArrayAdapter extends ArrayAdapter
|
|
||||||
{
|
|
||||||
private $item;
|
|
||||||
|
|
||||||
public function __construct(CacheItemInterface $item)
|
|
||||||
{
|
|
||||||
$this->item = $item;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getItem($key)
|
|
||||||
{
|
|
||||||
return $this->item;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function save(CacheItemInterface $item)
|
|
||||||
{
|
|
||||||
if ($item === $this->item) {
|
|
||||||
throw new \Exception('OK '.$item->get());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,92 +0,0 @@
|
||||||
<?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\Tests\Adapter;
|
|
||||||
|
|
||||||
use Symfony\Component\Cache\Adapter\AbstractAdapter;
|
|
||||||
use Symfony\Component\Cache\Adapter\RedisAdapter;
|
|
||||||
use Symfony\Component\Cache\Traits\RedisProxy;
|
|
||||||
|
|
||||||
class RedisAdapterTest extends AbstractRedisAdapterTest
|
|
||||||
{
|
|
||||||
public static function setUpBeforeClass()
|
|
||||||
{
|
|
||||||
parent::setUpBeforeClass();
|
|
||||||
self::$redis = AbstractAdapter::createConnection('redis://'.getenv('REDIS_HOST'), ['lazy' => true]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function createCachePool($defaultLifetime = 0)
|
|
||||||
{
|
|
||||||
$adapter = parent::createCachePool($defaultLifetime);
|
|
||||||
$this->assertInstanceOf(RedisProxy::class, self::$redis);
|
|
||||||
|
|
||||||
return $adapter;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testCreateConnection()
|
|
||||||
{
|
|
||||||
$redisHost = getenv('REDIS_HOST');
|
|
||||||
|
|
||||||
$redis = RedisAdapter::createConnection('redis://'.$redisHost);
|
|
||||||
$this->assertInstanceOf(\Redis::class, $redis);
|
|
||||||
$this->assertTrue($redis->isConnected());
|
|
||||||
$this->assertSame(0, $redis->getDbNum());
|
|
||||||
|
|
||||||
$redis = RedisAdapter::createConnection('redis://'.$redisHost.'/2');
|
|
||||||
$this->assertSame(2, $redis->getDbNum());
|
|
||||||
|
|
||||||
$redis = RedisAdapter::createConnection('redis://'.$redisHost, ['timeout' => 3]);
|
|
||||||
$this->assertEquals(3, $redis->getTimeout());
|
|
||||||
|
|
||||||
$redis = RedisAdapter::createConnection('redis://'.$redisHost.'?timeout=4');
|
|
||||||
$this->assertEquals(4, $redis->getTimeout());
|
|
||||||
|
|
||||||
$redis = RedisAdapter::createConnection('redis://'.$redisHost, ['read_timeout' => 5]);
|
|
||||||
$this->assertEquals(5, $redis->getReadTimeout());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @dataProvider provideFailedCreateConnection
|
|
||||||
*/
|
|
||||||
public function testFailedCreateConnection($dsn)
|
|
||||||
{
|
|
||||||
$this->expectException('Symfony\Component\Cache\Exception\InvalidArgumentException');
|
|
||||||
$this->expectExceptionMessage('Redis connection ');
|
|
||||||
RedisAdapter::createConnection($dsn);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function provideFailedCreateConnection()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
['redis://localhost:1234'],
|
|
||||||
['redis://foo@localhost'],
|
|
||||||
['redis://localhost/123'],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @dataProvider provideInvalidCreateConnection
|
|
||||||
*/
|
|
||||||
public function testInvalidCreateConnection($dsn)
|
|
||||||
{
|
|
||||||
$this->expectException('Symfony\Component\Cache\Exception\InvalidArgumentException');
|
|
||||||
$this->expectExceptionMessage('Invalid Redis DSN');
|
|
||||||
RedisAdapter::createConnection($dsn);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function provideInvalidCreateConnection()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
['foo://localhost'],
|
|
||||||
['redis://'],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
<?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\Tests\Adapter;
|
|
||||||
|
|
||||||
class RedisArrayAdapterTest extends AbstractRedisAdapterTest
|
|
||||||
{
|
|
||||||
public static function setUpBeforeClass()
|
|
||||||
{
|
|
||||||
parent::setupBeforeClass();
|
|
||||||
if (!class_exists('RedisArray')) {
|
|
||||||
self::markTestSkipped('The RedisArray class is required.');
|
|
||||||
}
|
|
||||||
self::$redis = new \RedisArray([getenv('REDIS_HOST')], ['lazy_connect' => true]);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
<?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\Tests\Adapter;
|
|
||||||
|
|
||||||
class RedisClusterAdapterTest extends AbstractRedisAdapterTest
|
|
||||||
{
|
|
||||||
public static function setUpBeforeClass()
|
|
||||||
{
|
|
||||||
if (!class_exists('RedisCluster')) {
|
|
||||||
self::markTestSkipped('The RedisCluster class is required.');
|
|
||||||
}
|
|
||||||
if (!$hosts = getenv('REDIS_CLUSTER_HOSTS')) {
|
|
||||||
self::markTestSkipped('REDIS_CLUSTER_HOSTS env var is not defined.');
|
|
||||||
}
|
|
||||||
|
|
||||||
self::$redis = new \RedisCluster(null, explode(' ', $hosts));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
<?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\Tests\Adapter;
|
|
||||||
|
|
||||||
use Symfony\Component\Cache\Adapter\SimpleCacheAdapter;
|
|
||||||
use Symfony\Component\Cache\Simple\ArrayCache;
|
|
||||||
use Symfony\Component\Cache\Simple\FilesystemCache;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @group time-sensitive
|
|
||||||
*/
|
|
||||||
class SimpleCacheAdapterTest extends AdapterTestCase
|
|
||||||
{
|
|
||||||
protected $skippedTests = [
|
|
||||||
'testPrune' => 'SimpleCache just proxies',
|
|
||||||
];
|
|
||||||
|
|
||||||
public function createCachePool($defaultLifetime = 0)
|
|
||||||
{
|
|
||||||
return new SimpleCacheAdapter(new FilesystemCache(), '', $defaultLifetime);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testValidCacheKeyWithNamespace()
|
|
||||||
{
|
|
||||||
$cache = new SimpleCacheAdapter(new ArrayCache(), 'some_namespace', 0);
|
|
||||||
$item = $cache->getItem('my_key');
|
|
||||||
$item->set('someValue');
|
|
||||||
$cache->save($item);
|
|
||||||
|
|
||||||
$this->assertTrue($cache->getItem('my_key')->isHit(), 'Stored item is successfully retrieved.');
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,338 +0,0 @@
|
||||||
<?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\Tests\Adapter;
|
|
||||||
|
|
||||||
use PHPUnit\Framework\MockObject\MockObject;
|
|
||||||
use Psr\Cache\CacheItemInterface;
|
|
||||||
use Symfony\Component\Cache\Adapter\AdapterInterface;
|
|
||||||
use Symfony\Component\Cache\Adapter\ArrayAdapter;
|
|
||||||
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
|
|
||||||
use Symfony\Component\Cache\Adapter\TagAwareAdapter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @group time-sensitive
|
|
||||||
*/
|
|
||||||
class TagAwareAdapterTest extends AdapterTestCase
|
|
||||||
{
|
|
||||||
public function createCachePool($defaultLifetime = 0)
|
|
||||||
{
|
|
||||||
return new TagAwareAdapter(new FilesystemAdapter('', $defaultLifetime));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function tearDownAfterClass()
|
|
||||||
{
|
|
||||||
FilesystemAdapterTest::rmdir(sys_get_temp_dir().'/symfony-cache');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testInvalidTag()
|
|
||||||
{
|
|
||||||
$this->expectException('Psr\Cache\InvalidArgumentException');
|
|
||||||
$pool = $this->createCachePool();
|
|
||||||
$item = $pool->getItem('foo');
|
|
||||||
$item->tag(':');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testInvalidateTags()
|
|
||||||
{
|
|
||||||
$pool = $this->createCachePool();
|
|
||||||
|
|
||||||
$i0 = $pool->getItem('i0');
|
|
||||||
$i1 = $pool->getItem('i1');
|
|
||||||
$i2 = $pool->getItem('i2');
|
|
||||||
$i3 = $pool->getItem('i3');
|
|
||||||
$foo = $pool->getItem('foo');
|
|
||||||
|
|
||||||
$pool->save($i0->tag('bar'));
|
|
||||||
$pool->save($i1->tag('foo'));
|
|
||||||
$pool->save($i2->tag('foo')->tag('bar'));
|
|
||||||
$pool->save($i3->tag('foo')->tag('baz'));
|
|
||||||
$pool->save($foo);
|
|
||||||
|
|
||||||
$pool->invalidateTags(['bar']);
|
|
||||||
|
|
||||||
$this->assertFalse($pool->getItem('i0')->isHit());
|
|
||||||
$this->assertTrue($pool->getItem('i1')->isHit());
|
|
||||||
$this->assertFalse($pool->getItem('i2')->isHit());
|
|
||||||
$this->assertTrue($pool->getItem('i3')->isHit());
|
|
||||||
$this->assertTrue($pool->getItem('foo')->isHit());
|
|
||||||
|
|
||||||
$pool->invalidateTags(['foo']);
|
|
||||||
|
|
||||||
$this->assertFalse($pool->getItem('i1')->isHit());
|
|
||||||
$this->assertFalse($pool->getItem('i3')->isHit());
|
|
||||||
$this->assertTrue($pool->getItem('foo')->isHit());
|
|
||||||
|
|
||||||
$anotherPoolInstance = $this->createCachePool();
|
|
||||||
|
|
||||||
$this->assertFalse($anotherPoolInstance->getItem('i1')->isHit());
|
|
||||||
$this->assertFalse($anotherPoolInstance->getItem('i3')->isHit());
|
|
||||||
$this->assertTrue($anotherPoolInstance->getItem('foo')->isHit());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testInvalidateCommits()
|
|
||||||
{
|
|
||||||
$pool1 = $this->createCachePool();
|
|
||||||
|
|
||||||
$foo = $pool1->getItem('foo');
|
|
||||||
$foo->tag('tag');
|
|
||||||
|
|
||||||
$pool1->saveDeferred($foo->set('foo'));
|
|
||||||
$pool1->invalidateTags(['tag']);
|
|
||||||
|
|
||||||
$pool2 = $this->createCachePool();
|
|
||||||
$foo = $pool2->getItem('foo');
|
|
||||||
|
|
||||||
$this->assertTrue($foo->isHit());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testTagsAreCleanedOnSave()
|
|
||||||
{
|
|
||||||
$pool = $this->createCachePool();
|
|
||||||
|
|
||||||
$i = $pool->getItem('k');
|
|
||||||
$pool->save($i->tag('foo'));
|
|
||||||
|
|
||||||
$i = $pool->getItem('k');
|
|
||||||
$pool->save($i->tag('bar'));
|
|
||||||
|
|
||||||
$pool->invalidateTags(['foo']);
|
|
||||||
$this->assertTrue($pool->getItem('k')->isHit());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testTagsAreCleanedOnDelete()
|
|
||||||
{
|
|
||||||
$pool = $this->createCachePool();
|
|
||||||
|
|
||||||
$i = $pool->getItem('k');
|
|
||||||
$pool->save($i->tag('foo'));
|
|
||||||
$pool->deleteItem('k');
|
|
||||||
|
|
||||||
$pool->save($pool->getItem('k'));
|
|
||||||
$pool->invalidateTags(['foo']);
|
|
||||||
|
|
||||||
$this->assertTrue($pool->getItem('k')->isHit());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testTagItemExpiry()
|
|
||||||
{
|
|
||||||
$pool = $this->createCachePool(10);
|
|
||||||
|
|
||||||
$item = $pool->getItem('foo');
|
|
||||||
$item->tag(['baz']);
|
|
||||||
$item->expiresAfter(100);
|
|
||||||
|
|
||||||
$pool->save($item);
|
|
||||||
$pool->invalidateTags(['baz']);
|
|
||||||
$this->assertFalse($pool->getItem('foo')->isHit());
|
|
||||||
|
|
||||||
sleep(20);
|
|
||||||
|
|
||||||
$this->assertFalse($pool->getItem('foo')->isHit());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testGetPreviousTags()
|
|
||||||
{
|
|
||||||
$pool = $this->createCachePool();
|
|
||||||
|
|
||||||
$i = $pool->getItem('k');
|
|
||||||
$pool->save($i->tag('foo'));
|
|
||||||
|
|
||||||
$i = $pool->getItem('k');
|
|
||||||
$this->assertSame(['foo' => 'foo'], $i->getPreviousTags());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testPrune()
|
|
||||||
{
|
|
||||||
$cache = new TagAwareAdapter($this->getPruneableMock());
|
|
||||||
$this->assertTrue($cache->prune());
|
|
||||||
|
|
||||||
$cache = new TagAwareAdapter($this->getNonPruneableMock());
|
|
||||||
$this->assertFalse($cache->prune());
|
|
||||||
|
|
||||||
$cache = new TagAwareAdapter($this->getFailingPruneableMock());
|
|
||||||
$this->assertFalse($cache->prune());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testKnownTagVersionsTtl()
|
|
||||||
{
|
|
||||||
$itemsPool = new FilesystemAdapter('', 10);
|
|
||||||
$tagsPool = $this
|
|
||||||
->getMockBuilder(AdapterInterface::class)
|
|
||||||
->getMock();
|
|
||||||
|
|
||||||
$pool = new TagAwareAdapter($itemsPool, $tagsPool, 10);
|
|
||||||
|
|
||||||
$item = $pool->getItem('foo');
|
|
||||||
$item->tag(['baz']);
|
|
||||||
$item->expiresAfter(100);
|
|
||||||
|
|
||||||
$tag = $this->getMockBuilder(CacheItemInterface::class)->getMock();
|
|
||||||
$tag->expects(self::exactly(2))->method('get')->willReturn(10);
|
|
||||||
|
|
||||||
$tagsPool->expects(self::exactly(2))->method('getItems')->willReturn([
|
|
||||||
'baz'.TagAwareAdapter::TAGS_PREFIX => $tag,
|
|
||||||
]);
|
|
||||||
|
|
||||||
$pool->save($item);
|
|
||||||
$this->assertTrue($pool->getItem('foo')->isHit());
|
|
||||||
$this->assertTrue($pool->getItem('foo')->isHit());
|
|
||||||
|
|
||||||
sleep(20);
|
|
||||||
|
|
||||||
$this->assertTrue($pool->getItem('foo')->isHit());
|
|
||||||
|
|
||||||
sleep(5);
|
|
||||||
|
|
||||||
$this->assertTrue($pool->getItem('foo')->isHit());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testTagEntryIsCreatedForItemWithoutTags()
|
|
||||||
{
|
|
||||||
$pool = $this->createCachePool();
|
|
||||||
|
|
||||||
$itemKey = 'foo';
|
|
||||||
$item = $pool->getItem($itemKey);
|
|
||||||
$pool->save($item);
|
|
||||||
|
|
||||||
$adapter = new FilesystemAdapter();
|
|
||||||
$this->assertTrue($adapter->hasItem(TagAwareAdapter::TAGS_PREFIX.$itemKey));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testHasItemReturnsFalseWhenPoolDoesNotHaveItemTags()
|
|
||||||
{
|
|
||||||
$pool = $this->createCachePool();
|
|
||||||
|
|
||||||
$itemKey = 'foo';
|
|
||||||
$item = $pool->getItem($itemKey);
|
|
||||||
$pool->save($item);
|
|
||||||
|
|
||||||
$anotherPool = $this->createCachePool();
|
|
||||||
|
|
||||||
$adapter = new FilesystemAdapter();
|
|
||||||
$adapter->deleteItem(TagAwareAdapter::TAGS_PREFIX.$itemKey); //simulate item losing tags pair
|
|
||||||
|
|
||||||
$this->assertFalse($anotherPool->hasItem($itemKey));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testGetItemReturnsCacheMissWhenPoolDoesNotHaveItemTags()
|
|
||||||
{
|
|
||||||
$pool = $this->createCachePool();
|
|
||||||
|
|
||||||
$itemKey = 'foo';
|
|
||||||
$item = $pool->getItem($itemKey);
|
|
||||||
$pool->save($item);
|
|
||||||
|
|
||||||
$anotherPool = $this->createCachePool();
|
|
||||||
|
|
||||||
$adapter = new FilesystemAdapter();
|
|
||||||
$adapter->deleteItem(TagAwareAdapter::TAGS_PREFIX.$itemKey); //simulate item losing tags pair
|
|
||||||
|
|
||||||
$item = $anotherPool->getItem($itemKey);
|
|
||||||
$this->assertFalse($item->isHit());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testHasItemReturnsFalseWhenPoolDoesNotHaveItemAndOnlyHasTags()
|
|
||||||
{
|
|
||||||
$pool = $this->createCachePool();
|
|
||||||
|
|
||||||
$itemKey = 'foo';
|
|
||||||
$item = $pool->getItem($itemKey);
|
|
||||||
$pool->save($item);
|
|
||||||
|
|
||||||
$anotherPool = $this->createCachePool();
|
|
||||||
|
|
||||||
$adapter = new FilesystemAdapter();
|
|
||||||
$adapter->deleteItem($itemKey); //simulate losing item but keeping tags
|
|
||||||
|
|
||||||
$this->assertFalse($anotherPool->hasItem($itemKey));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testInvalidateTagsWithArrayAdapter()
|
|
||||||
{
|
|
||||||
$adapter = new TagAwareAdapter(new ArrayAdapter());
|
|
||||||
|
|
||||||
$item = $adapter->getItem('foo');
|
|
||||||
|
|
||||||
$this->assertFalse($item->isHit());
|
|
||||||
|
|
||||||
$item->tag('bar');
|
|
||||||
$item->expiresAfter(100);
|
|
||||||
$adapter->save($item);
|
|
||||||
|
|
||||||
$this->assertTrue($adapter->getItem('foo')->isHit());
|
|
||||||
|
|
||||||
$adapter->invalidateTags(['bar']);
|
|
||||||
|
|
||||||
$this->assertFalse($adapter->getItem('foo')->isHit());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testGetItemReturnsCacheMissWhenPoolDoesNotHaveItemAndOnlyHasTags()
|
|
||||||
{
|
|
||||||
$pool = $this->createCachePool();
|
|
||||||
|
|
||||||
$itemKey = 'foo';
|
|
||||||
$item = $pool->getItem($itemKey);
|
|
||||||
$pool->save($item);
|
|
||||||
|
|
||||||
$anotherPool = $this->createCachePool();
|
|
||||||
|
|
||||||
$adapter = new FilesystemAdapter();
|
|
||||||
$adapter->deleteItem($itemKey); //simulate losing item but keeping tags
|
|
||||||
|
|
||||||
$item = $anotherPool->getItem($itemKey);
|
|
||||||
$this->assertFalse($item->isHit());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return MockObject|PruneableCacheInterface
|
|
||||||
*/
|
|
||||||
private function getPruneableMock()
|
|
||||||
{
|
|
||||||
$pruneable = $this
|
|
||||||
->getMockBuilder(PruneableCacheInterface::class)
|
|
||||||
->getMock();
|
|
||||||
|
|
||||||
$pruneable
|
|
||||||
->expects($this->atLeastOnce())
|
|
||||||
->method('prune')
|
|
||||||
->willReturn(true);
|
|
||||||
|
|
||||||
return $pruneable;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return MockObject|PruneableCacheInterface
|
|
||||||
*/
|
|
||||||
private function getFailingPruneableMock()
|
|
||||||
{
|
|
||||||
$pruneable = $this
|
|
||||||
->getMockBuilder(PruneableCacheInterface::class)
|
|
||||||
->getMock();
|
|
||||||
|
|
||||||
$pruneable
|
|
||||||
->expects($this->atLeastOnce())
|
|
||||||
->method('prune')
|
|
||||||
->willReturn(false);
|
|
||||||
|
|
||||||
return $pruneable;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return MockObject|AdapterInterface
|
|
||||||
*/
|
|
||||||
private function getNonPruneableMock()
|
|
||||||
{
|
|
||||||
return $this
|
|
||||||
->getMockBuilder(AdapterInterface::class)
|
|
||||||
->getMock();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,38 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Symfony\Component\Cache\Tests\Adapter;
|
|
||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
|
||||||
use Psr\Cache\CacheItemPoolInterface;
|
|
||||||
use Symfony\Component\Cache\Adapter\ArrayAdapter;
|
|
||||||
use Symfony\Component\Cache\Adapter\ProxyAdapter;
|
|
||||||
use Symfony\Component\Cache\Adapter\TagAwareAdapter;
|
|
||||||
use Symfony\Component\Cache\Tests\Fixtures\ExternalAdapter;
|
|
||||||
|
|
||||||
class TagAwareAndProxyAdapterIntegrationTest extends TestCase
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @dataProvider dataProvider
|
|
||||||
*/
|
|
||||||
public function testIntegrationUsingProxiedAdapter(CacheItemPoolInterface $proxiedAdapter)
|
|
||||||
{
|
|
||||||
$cache = new TagAwareAdapter(new ProxyAdapter($proxiedAdapter));
|
|
||||||
|
|
||||||
$item = $cache->getItem('foo');
|
|
||||||
$item->tag(['tag1', 'tag2']);
|
|
||||||
$item->set('bar');
|
|
||||||
$cache->save($item);
|
|
||||||
|
|
||||||
$this->assertSame('bar', $cache->getItem('foo')->get());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function dataProvider()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
[new ArrayAdapter()],
|
|
||||||
// also testing with a non-AdapterInterface implementation
|
|
||||||
// because the ProxyAdapter behaves slightly different for those
|
|
||||||
[new ExternalAdapter()],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,191 +0,0 @@
|
||||||
<?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\Tests\Adapter;
|
|
||||||
|
|
||||||
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
|
|
||||||
use Symfony\Component\Cache\Adapter\TraceableAdapter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @group time-sensitive
|
|
||||||
*/
|
|
||||||
class TraceableAdapterTest extends AdapterTestCase
|
|
||||||
{
|
|
||||||
protected $skippedTests = [
|
|
||||||
'testPrune' => 'TraceableAdapter just proxies',
|
|
||||||
];
|
|
||||||
|
|
||||||
public function createCachePool($defaultLifetime = 0)
|
|
||||||
{
|
|
||||||
return new TraceableAdapter(new FilesystemAdapter('', $defaultLifetime));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testGetItemMissTrace()
|
|
||||||
{
|
|
||||||
$pool = $this->createCachePool();
|
|
||||||
$pool->getItem('k');
|
|
||||||
$calls = $pool->getCalls();
|
|
||||||
$this->assertCount(1, $calls);
|
|
||||||
|
|
||||||
$call = $calls[0];
|
|
||||||
$this->assertSame('getItem', $call->name);
|
|
||||||
$this->assertSame(['k' => false], $call->result);
|
|
||||||
$this->assertSame(0, $call->hits);
|
|
||||||
$this->assertSame(1, $call->misses);
|
|
||||||
$this->assertNotEmpty($call->start);
|
|
||||||
$this->assertNotEmpty($call->end);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testGetItemHitTrace()
|
|
||||||
{
|
|
||||||
$pool = $this->createCachePool();
|
|
||||||
$item = $pool->getItem('k')->set('foo');
|
|
||||||
$pool->save($item);
|
|
||||||
$pool->getItem('k');
|
|
||||||
$calls = $pool->getCalls();
|
|
||||||
$this->assertCount(3, $calls);
|
|
||||||
|
|
||||||
$call = $calls[2];
|
|
||||||
$this->assertSame(1, $call->hits);
|
|
||||||
$this->assertSame(0, $call->misses);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testGetItemsMissTrace()
|
|
||||||
{
|
|
||||||
$pool = $this->createCachePool();
|
|
||||||
$arg = ['k0', 'k1'];
|
|
||||||
$items = $pool->getItems($arg);
|
|
||||||
foreach ($items as $item) {
|
|
||||||
}
|
|
||||||
$calls = $pool->getCalls();
|
|
||||||
$this->assertCount(1, $calls);
|
|
||||||
|
|
||||||
$call = $calls[0];
|
|
||||||
$this->assertSame('getItems', $call->name);
|
|
||||||
$this->assertSame(['k0' => false, 'k1' => false], $call->result);
|
|
||||||
$this->assertSame(2, $call->misses);
|
|
||||||
$this->assertNotEmpty($call->start);
|
|
||||||
$this->assertNotEmpty($call->end);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testHasItemMissTrace()
|
|
||||||
{
|
|
||||||
$pool = $this->createCachePool();
|
|
||||||
$pool->hasItem('k');
|
|
||||||
$calls = $pool->getCalls();
|
|
||||||
$this->assertCount(1, $calls);
|
|
||||||
|
|
||||||
$call = $calls[0];
|
|
||||||
$this->assertSame('hasItem', $call->name);
|
|
||||||
$this->assertSame(['k' => false], $call->result);
|
|
||||||
$this->assertNotEmpty($call->start);
|
|
||||||
$this->assertNotEmpty($call->end);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testHasItemHitTrace()
|
|
||||||
{
|
|
||||||
$pool = $this->createCachePool();
|
|
||||||
$item = $pool->getItem('k')->set('foo');
|
|
||||||
$pool->save($item);
|
|
||||||
$pool->hasItem('k');
|
|
||||||
$calls = $pool->getCalls();
|
|
||||||
$this->assertCount(3, $calls);
|
|
||||||
|
|
||||||
$call = $calls[2];
|
|
||||||
$this->assertSame('hasItem', $call->name);
|
|
||||||
$this->assertSame(['k' => true], $call->result);
|
|
||||||
$this->assertNotEmpty($call->start);
|
|
||||||
$this->assertNotEmpty($call->end);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testDeleteItemTrace()
|
|
||||||
{
|
|
||||||
$pool = $this->createCachePool();
|
|
||||||
$pool->deleteItem('k');
|
|
||||||
$calls = $pool->getCalls();
|
|
||||||
$this->assertCount(1, $calls);
|
|
||||||
|
|
||||||
$call = $calls[0];
|
|
||||||
$this->assertSame('deleteItem', $call->name);
|
|
||||||
$this->assertSame(['k' => true], $call->result);
|
|
||||||
$this->assertSame(0, $call->hits);
|
|
||||||
$this->assertSame(0, $call->misses);
|
|
||||||
$this->assertNotEmpty($call->start);
|
|
||||||
$this->assertNotEmpty($call->end);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testDeleteItemsTrace()
|
|
||||||
{
|
|
||||||
$pool = $this->createCachePool();
|
|
||||||
$arg = ['k0', 'k1'];
|
|
||||||
$pool->deleteItems($arg);
|
|
||||||
$calls = $pool->getCalls();
|
|
||||||
$this->assertCount(1, $calls);
|
|
||||||
|
|
||||||
$call = $calls[0];
|
|
||||||
$this->assertSame('deleteItems', $call->name);
|
|
||||||
$this->assertSame(['keys' => $arg, 'result' => true], $call->result);
|
|
||||||
$this->assertSame(0, $call->hits);
|
|
||||||
$this->assertSame(0, $call->misses);
|
|
||||||
$this->assertNotEmpty($call->start);
|
|
||||||
$this->assertNotEmpty($call->end);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testSaveTrace()
|
|
||||||
{
|
|
||||||
$pool = $this->createCachePool();
|
|
||||||
$item = $pool->getItem('k')->set('foo');
|
|
||||||
$pool->save($item);
|
|
||||||
$calls = $pool->getCalls();
|
|
||||||
$this->assertCount(2, $calls);
|
|
||||||
|
|
||||||
$call = $calls[1];
|
|
||||||
$this->assertSame('save', $call->name);
|
|
||||||
$this->assertSame(['k' => true], $call->result);
|
|
||||||
$this->assertSame(0, $call->hits);
|
|
||||||
$this->assertSame(0, $call->misses);
|
|
||||||
$this->assertNotEmpty($call->start);
|
|
||||||
$this->assertNotEmpty($call->end);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testSaveDeferredTrace()
|
|
||||||
{
|
|
||||||
$pool = $this->createCachePool();
|
|
||||||
$item = $pool->getItem('k')->set('foo');
|
|
||||||
$pool->saveDeferred($item);
|
|
||||||
$calls = $pool->getCalls();
|
|
||||||
$this->assertCount(2, $calls);
|
|
||||||
|
|
||||||
$call = $calls[1];
|
|
||||||
$this->assertSame('saveDeferred', $call->name);
|
|
||||||
$this->assertSame(['k' => true], $call->result);
|
|
||||||
$this->assertSame(0, $call->hits);
|
|
||||||
$this->assertSame(0, $call->misses);
|
|
||||||
$this->assertNotEmpty($call->start);
|
|
||||||
$this->assertNotEmpty($call->end);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testCommitTrace()
|
|
||||||
{
|
|
||||||
$pool = $this->createCachePool();
|
|
||||||
$pool->commit();
|
|
||||||
$calls = $pool->getCalls();
|
|
||||||
$this->assertCount(1, $calls);
|
|
||||||
|
|
||||||
$call = $calls[0];
|
|
||||||
$this->assertSame('commit', $call->name);
|
|
||||||
$this->assertTrue($call->result);
|
|
||||||
$this->assertSame(0, $call->hits);
|
|
||||||
$this->assertSame(0, $call->misses);
|
|
||||||
$this->assertNotEmpty($call->start);
|
|
||||||
$this->assertNotEmpty($call->end);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,37 +0,0 @@
|
||||||
<?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\Tests\Adapter;
|
|
||||||
|
|
||||||
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
|
|
||||||
use Symfony\Component\Cache\Adapter\TagAwareAdapter;
|
|
||||||
use Symfony\Component\Cache\Adapter\TraceableTagAwareAdapter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @group time-sensitive
|
|
||||||
*/
|
|
||||||
class TraceableTagAwareAdapterTest extends TraceableAdapterTest
|
|
||||||
{
|
|
||||||
public function testInvalidateTags()
|
|
||||||
{
|
|
||||||
$pool = new TraceableTagAwareAdapter(new TagAwareAdapter(new FilesystemAdapter()));
|
|
||||||
$pool->invalidateTags(['foo']);
|
|
||||||
$calls = $pool->getCalls();
|
|
||||||
$this->assertCount(1, $calls);
|
|
||||||
|
|
||||||
$call = $calls[0];
|
|
||||||
$this->assertSame('invalidateTags', $call->name);
|
|
||||||
$this->assertSame(0, $call->hits);
|
|
||||||
$this->assertSame(0, $call->misses);
|
|
||||||
$this->assertNotEmpty($call->start);
|
|
||||||
$this->assertNotEmpty($call->end);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,77 +0,0 @@
|
||||||
<?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\Tests;
|
|
||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
|
||||||
use Symfony\Component\Cache\CacheItem;
|
|
||||||
|
|
||||||
class CacheItemTest extends TestCase
|
|
||||||
{
|
|
||||||
public function testValidKey()
|
|
||||||
{
|
|
||||||
$this->assertSame('foo', CacheItem::validateKey('foo'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @dataProvider provideInvalidKey
|
|
||||||
*/
|
|
||||||
public function testInvalidKey($key)
|
|
||||||
{
|
|
||||||
$this->expectException('Symfony\Component\Cache\Exception\InvalidArgumentException');
|
|
||||||
$this->expectExceptionMessage('Cache key');
|
|
||||||
CacheItem::validateKey($key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function provideInvalidKey()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
[''],
|
|
||||||
['{'],
|
|
||||||
['}'],
|
|
||||||
['('],
|
|
||||||
[')'],
|
|
||||||
['/'],
|
|
||||||
['\\'],
|
|
||||||
['@'],
|
|
||||||
[':'],
|
|
||||||
[true],
|
|
||||||
[null],
|
|
||||||
[1],
|
|
||||||
[1.1],
|
|
||||||
[[[]]],
|
|
||||||
[new \Exception('foo')],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testTag()
|
|
||||||
{
|
|
||||||
$item = new CacheItem();
|
|
||||||
|
|
||||||
$this->assertSame($item, $item->tag('foo'));
|
|
||||||
$this->assertSame($item, $item->tag(['bar', 'baz']));
|
|
||||||
|
|
||||||
\call_user_func(\Closure::bind(function () use ($item) {
|
|
||||||
$this->assertSame(['foo' => 'foo', 'bar' => 'bar', 'baz' => 'baz'], $item->tags);
|
|
||||||
}, $this, CacheItem::class));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @dataProvider provideInvalidKey
|
|
||||||
*/
|
|
||||||
public function testInvalidTag($tag)
|
|
||||||
{
|
|
||||||
$this->expectException('Symfony\Component\Cache\Exception\InvalidArgumentException');
|
|
||||||
$this->expectExceptionMessage('Cache tag');
|
|
||||||
$item = new CacheItem();
|
|
||||||
$item->tag($tag);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,45 +0,0 @@
|
||||||
<?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\Tests;
|
|
||||||
|
|
||||||
use Doctrine\Common\Cache\CacheProvider;
|
|
||||||
use PHPUnit\Framework\TestCase;
|
|
||||||
use Symfony\Component\Cache\Adapter\ArrayAdapter;
|
|
||||||
use Symfony\Component\Cache\DoctrineProvider;
|
|
||||||
|
|
||||||
class DoctrineProviderTest extends TestCase
|
|
||||||
{
|
|
||||||
public function testProvider()
|
|
||||||
{
|
|
||||||
$pool = new ArrayAdapter();
|
|
||||||
$cache = new DoctrineProvider($pool);
|
|
||||||
|
|
||||||
$this->assertInstanceOf(CacheProvider::class, $cache);
|
|
||||||
|
|
||||||
$key = '{}()/\@:';
|
|
||||||
|
|
||||||
$this->assertTrue($cache->delete($key));
|
|
||||||
$this->assertFalse($cache->contains($key));
|
|
||||||
|
|
||||||
$this->assertTrue($cache->save($key, 'bar'));
|
|
||||||
$this->assertTrue($cache->contains($key));
|
|
||||||
$this->assertSame('bar', $cache->fetch($key));
|
|
||||||
|
|
||||||
$this->assertTrue($cache->delete($key));
|
|
||||||
$this->assertFalse($cache->fetch($key));
|
|
||||||
$this->assertTrue($cache->save($key, 'bar'));
|
|
||||||
|
|
||||||
$cache->flushAll();
|
|
||||||
$this->assertFalse($cache->fetch($key));
|
|
||||||
$this->assertFalse($cache->contains($key));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,52 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Symfony\Component\Cache\Tests\Fixtures;
|
|
||||||
|
|
||||||
use Doctrine\Common\Cache\CacheProvider;
|
|
||||||
|
|
||||||
class ArrayCache extends CacheProvider
|
|
||||||
{
|
|
||||||
private $data = [];
|
|
||||||
|
|
||||||
protected function doFetch($id)
|
|
||||||
{
|
|
||||||
return $this->doContains($id) ? $this->data[$id][0] : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function doContains($id)
|
|
||||||
{
|
|
||||||
if (!isset($this->data[$id])) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$expiry = $this->data[$id][1];
|
|
||||||
|
|
||||||
return !$expiry || time() < $expiry || !$this->doDelete($id);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function doSave($id, $data, $lifeTime = 0)
|
|
||||||
{
|
|
||||||
$this->data[$id] = [$data, $lifeTime ? time() + $lifeTime : false];
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function doDelete($id)
|
|
||||||
{
|
|
||||||
unset($this->data[$id]);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function doFlush()
|
|
||||||
{
|
|
||||||
$this->data = [];
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function doGetStats()
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,76 +0,0 @@
|
||||||
<?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\Tests\Fixtures;
|
|
||||||
|
|
||||||
use Psr\Cache\CacheItemInterface;
|
|
||||||
use Psr\Cache\CacheItemPoolInterface;
|
|
||||||
use Symfony\Component\Cache\Adapter\ArrayAdapter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adapter not implementing the {@see \Symfony\Component\Cache\Adapter\AdapterInterface}.
|
|
||||||
*
|
|
||||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
|
||||||
*/
|
|
||||||
class ExternalAdapter implements CacheItemPoolInterface
|
|
||||||
{
|
|
||||||
private $cache;
|
|
||||||
|
|
||||||
public function __construct($defaultLifetime = 0)
|
|
||||||
{
|
|
||||||
$this->cache = new ArrayAdapter($defaultLifetime);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getItem($key)
|
|
||||||
{
|
|
||||||
return $this->cache->getItem($key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getItems(array $keys = [])
|
|
||||||
{
|
|
||||||
return $this->cache->getItems($keys);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function hasItem($key)
|
|
||||||
{
|
|
||||||
return $this->cache->hasItem($key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function clear()
|
|
||||||
{
|
|
||||||
return $this->cache->clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function deleteItem($key)
|
|
||||||
{
|
|
||||||
return $this->cache->deleteItem($key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function deleteItems(array $keys)
|
|
||||||
{
|
|
||||||
return $this->cache->deleteItems($keys);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function save(CacheItemInterface $item)
|
|
||||||
{
|
|
||||||
return $this->cache->save($item);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function saveDeferred(CacheItemInterface $item)
|
|
||||||
{
|
|
||||||
return $this->cache->saveDeferred($item);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function commit()
|
|
||||||
{
|
|
||||||
return $this->cache->commit();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,47 +0,0 @@
|
||||||
<?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\Tests\Simple;
|
|
||||||
|
|
||||||
use Symfony\Component\Cache\Simple\RedisCache;
|
|
||||||
|
|
||||||
abstract class AbstractRedisCacheTest extends CacheTestCase
|
|
||||||
{
|
|
||||||
protected $skippedTests = [
|
|
||||||
'testSetTtl' => 'Testing expiration slows down the test suite',
|
|
||||||
'testSetMultipleTtl' => 'Testing expiration slows down the test suite',
|
|
||||||
'testDefaultLifeTime' => 'Testing expiration slows down the test suite',
|
|
||||||
];
|
|
||||||
|
|
||||||
protected static $redis;
|
|
||||||
|
|
||||||
public function createSimpleCache($defaultLifetime = 0)
|
|
||||||
{
|
|
||||||
return new RedisCache(self::$redis, str_replace('\\', '.', __CLASS__), $defaultLifetime);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function setUpBeforeClass()
|
|
||||||
{
|
|
||||||
if (!\extension_loaded('redis')) {
|
|
||||||
self::markTestSkipped('Extension redis required.');
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
(new \Redis())->connect(getenv('REDIS_HOST'));
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
self::markTestSkipped($e->getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function tearDownAfterClass()
|
|
||||||
{
|
|
||||||
self::$redis = null;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
<?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\Tests\Simple;
|
|
||||||
|
|
||||||
use Symfony\Component\Cache\Simple\ApcuCache;
|
|
||||||
|
|
||||||
class ApcuCacheTest extends CacheTestCase
|
|
||||||
{
|
|
||||||
protected $skippedTests = [
|
|
||||||
'testSetTtl' => 'Testing expiration slows down the test suite',
|
|
||||||
'testSetMultipleTtl' => 'Testing expiration slows down the test suite',
|
|
||||||
'testDefaultLifeTime' => 'Testing expiration slows down the test suite',
|
|
||||||
];
|
|
||||||
|
|
||||||
public function createSimpleCache($defaultLifetime = 0)
|
|
||||||
{
|
|
||||||
if (!\function_exists('apcu_fetch') || !filter_var(ini_get('apc.enabled'), \FILTER_VALIDATE_BOOLEAN) || ('cli' === \PHP_SAPI && !filter_var(ini_get('apc.enable_cli'), \FILTER_VALIDATE_BOOLEAN))) {
|
|
||||||
$this->markTestSkipped('APCu extension is required.');
|
|
||||||
}
|
|
||||||
if ('\\' === \DIRECTORY_SEPARATOR) {
|
|
||||||
$this->markTestSkipped('Fails transiently on Windows.');
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ApcuCache(str_replace('\\', '.', __CLASS__), $defaultLifetime);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
<?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\Tests\Simple;
|
|
||||||
|
|
||||||
use Symfony\Component\Cache\Simple\ArrayCache;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @group time-sensitive
|
|
||||||
*/
|
|
||||||
class ArrayCacheTest extends CacheTestCase
|
|
||||||
{
|
|
||||||
public function createSimpleCache($defaultLifetime = 0)
|
|
||||||
{
|
|
||||||
return new ArrayCache($defaultLifetime);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,150 +0,0 @@
|
||||||
<?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\Tests\Simple;
|
|
||||||
|
|
||||||
use Cache\IntegrationTests\SimpleCacheTest;
|
|
||||||
use Psr\SimpleCache\CacheInterface;
|
|
||||||
use Symfony\Component\Cache\PruneableInterface;
|
|
||||||
|
|
||||||
abstract class CacheTestCase extends SimpleCacheTest
|
|
||||||
{
|
|
||||||
protected function setUp()
|
|
||||||
{
|
|
||||||
parent::setUp();
|
|
||||||
|
|
||||||
if (!\array_key_exists('testPrune', $this->skippedTests) && !$this->createSimpleCache() instanceof PruneableInterface) {
|
|
||||||
$this->skippedTests['testPrune'] = 'Not a pruneable cache pool.';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function validKeys()
|
|
||||||
{
|
|
||||||
if (\defined('HHVM_VERSION')) {
|
|
||||||
return parent::validKeys();
|
|
||||||
}
|
|
||||||
|
|
||||||
return array_merge(parent::validKeys(), [["a\0b"]]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testDefaultLifeTime()
|
|
||||||
{
|
|
||||||
if (isset($this->skippedTests[__FUNCTION__])) {
|
|
||||||
$this->markTestSkipped($this->skippedTests[__FUNCTION__]);
|
|
||||||
}
|
|
||||||
|
|
||||||
$cache = $this->createSimpleCache(2);
|
|
||||||
$cache->clear();
|
|
||||||
|
|
||||||
$cache->set('key.dlt', 'value');
|
|
||||||
sleep(1);
|
|
||||||
|
|
||||||
$this->assertSame('value', $cache->get('key.dlt'));
|
|
||||||
|
|
||||||
sleep(2);
|
|
||||||
$this->assertNull($cache->get('key.dlt'));
|
|
||||||
|
|
||||||
$cache->clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testNotUnserializable()
|
|
||||||
{
|
|
||||||
if (isset($this->skippedTests[__FUNCTION__])) {
|
|
||||||
$this->markTestSkipped($this->skippedTests[__FUNCTION__]);
|
|
||||||
}
|
|
||||||
|
|
||||||
$cache = $this->createSimpleCache();
|
|
||||||
$cache->clear();
|
|
||||||
|
|
||||||
$cache->set('foo', new NotUnserializable());
|
|
||||||
|
|
||||||
$this->assertNull($cache->get('foo'));
|
|
||||||
|
|
||||||
$cache->setMultiple(['foo' => new NotUnserializable()]);
|
|
||||||
|
|
||||||
foreach ($cache->getMultiple(['foo']) as $value) {
|
|
||||||
}
|
|
||||||
$this->assertNull($value);
|
|
||||||
|
|
||||||
$cache->clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testPrune()
|
|
||||||
{
|
|
||||||
if (isset($this->skippedTests[__FUNCTION__])) {
|
|
||||||
$this->markTestSkipped($this->skippedTests[__FUNCTION__]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!method_exists($this, 'isPruned')) {
|
|
||||||
$this->fail('Test classes for pruneable caches must implement `isPruned($cache, $name)` method.');
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @var PruneableInterface|CacheInterface $cache */
|
|
||||||
$cache = $this->createSimpleCache();
|
|
||||||
$cache->clear();
|
|
||||||
|
|
||||||
$cache->set('foo', 'foo-val', new \DateInterval('PT05S'));
|
|
||||||
$cache->set('bar', 'bar-val', new \DateInterval('PT10S'));
|
|
||||||
$cache->set('baz', 'baz-val', new \DateInterval('PT15S'));
|
|
||||||
$cache->set('qux', 'qux-val', new \DateInterval('PT20S'));
|
|
||||||
|
|
||||||
sleep(30);
|
|
||||||
$cache->prune();
|
|
||||||
$this->assertTrue($this->isPruned($cache, 'foo'));
|
|
||||||
$this->assertTrue($this->isPruned($cache, 'bar'));
|
|
||||||
$this->assertTrue($this->isPruned($cache, 'baz'));
|
|
||||||
$this->assertTrue($this->isPruned($cache, 'qux'));
|
|
||||||
|
|
||||||
$cache->set('foo', 'foo-val');
|
|
||||||
$cache->set('bar', 'bar-val', new \DateInterval('PT20S'));
|
|
||||||
$cache->set('baz', 'baz-val', new \DateInterval('PT40S'));
|
|
||||||
$cache->set('qux', 'qux-val', new \DateInterval('PT80S'));
|
|
||||||
|
|
||||||
$cache->prune();
|
|
||||||
$this->assertFalse($this->isPruned($cache, 'foo'));
|
|
||||||
$this->assertFalse($this->isPruned($cache, 'bar'));
|
|
||||||
$this->assertFalse($this->isPruned($cache, 'baz'));
|
|
||||||
$this->assertFalse($this->isPruned($cache, 'qux'));
|
|
||||||
|
|
||||||
sleep(30);
|
|
||||||
$cache->prune();
|
|
||||||
$this->assertFalse($this->isPruned($cache, 'foo'));
|
|
||||||
$this->assertTrue($this->isPruned($cache, 'bar'));
|
|
||||||
$this->assertFalse($this->isPruned($cache, 'baz'));
|
|
||||||
$this->assertFalse($this->isPruned($cache, 'qux'));
|
|
||||||
|
|
||||||
sleep(30);
|
|
||||||
$cache->prune();
|
|
||||||
$this->assertFalse($this->isPruned($cache, 'foo'));
|
|
||||||
$this->assertTrue($this->isPruned($cache, 'baz'));
|
|
||||||
$this->assertFalse($this->isPruned($cache, 'qux'));
|
|
||||||
|
|
||||||
sleep(30);
|
|
||||||
$cache->prune();
|
|
||||||
$this->assertFalse($this->isPruned($cache, 'foo'));
|
|
||||||
$this->assertTrue($this->isPruned($cache, 'qux'));
|
|
||||||
|
|
||||||
$cache->clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class NotUnserializable implements \Serializable
|
|
||||||
{
|
|
||||||
public function serialize()
|
|
||||||
{
|
|
||||||
return serialize(123);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function unserialize($ser)
|
|
||||||
{
|
|
||||||
throw new \Exception(__CLASS__);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,113 +0,0 @@
|
||||||
<?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\Tests\Simple;
|
|
||||||
|
|
||||||
use PHPUnit\Framework\MockObject\MockObject;
|
|
||||||
use Psr\SimpleCache\CacheInterface;
|
|
||||||
use Symfony\Component\Cache\PruneableInterface;
|
|
||||||
use Symfony\Component\Cache\Simple\ArrayCache;
|
|
||||||
use Symfony\Component\Cache\Simple\ChainCache;
|
|
||||||
use Symfony\Component\Cache\Simple\FilesystemCache;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @group time-sensitive
|
|
||||||
*/
|
|
||||||
class ChainCacheTest extends CacheTestCase
|
|
||||||
{
|
|
||||||
public function createSimpleCache($defaultLifetime = 0)
|
|
||||||
{
|
|
||||||
return new ChainCache([new ArrayCache($defaultLifetime), new FilesystemCache('', $defaultLifetime)], $defaultLifetime);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testEmptyCachesException()
|
|
||||||
{
|
|
||||||
$this->expectException('Symfony\Component\Cache\Exception\InvalidArgumentException');
|
|
||||||
$this->expectExceptionMessage('At least one cache must be specified.');
|
|
||||||
new ChainCache([]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testInvalidCacheException()
|
|
||||||
{
|
|
||||||
$this->expectException('Symfony\Component\Cache\Exception\InvalidArgumentException');
|
|
||||||
$this->expectExceptionMessage('The class "stdClass" does not implement');
|
|
||||||
new ChainCache([new \stdClass()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testPrune()
|
|
||||||
{
|
|
||||||
if (isset($this->skippedTests[__FUNCTION__])) {
|
|
||||||
$this->markTestSkipped($this->skippedTests[__FUNCTION__]);
|
|
||||||
}
|
|
||||||
|
|
||||||
$cache = new ChainCache([
|
|
||||||
$this->getPruneableMock(),
|
|
||||||
$this->getNonPruneableMock(),
|
|
||||||
$this->getPruneableMock(),
|
|
||||||
]);
|
|
||||||
$this->assertTrue($cache->prune());
|
|
||||||
|
|
||||||
$cache = new ChainCache([
|
|
||||||
$this->getPruneableMock(),
|
|
||||||
$this->getFailingPruneableMock(),
|
|
||||||
$this->getPruneableMock(),
|
|
||||||
]);
|
|
||||||
$this->assertFalse($cache->prune());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return MockObject|PruneableCacheInterface
|
|
||||||
*/
|
|
||||||
private function getPruneableMock()
|
|
||||||
{
|
|
||||||
$pruneable = $this
|
|
||||||
->getMockBuilder(PruneableCacheInterface::class)
|
|
||||||
->getMock();
|
|
||||||
|
|
||||||
$pruneable
|
|
||||||
->expects($this->atLeastOnce())
|
|
||||||
->method('prune')
|
|
||||||
->willReturn(true);
|
|
||||||
|
|
||||||
return $pruneable;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return MockObject|PruneableCacheInterface
|
|
||||||
*/
|
|
||||||
private function getFailingPruneableMock()
|
|
||||||
{
|
|
||||||
$pruneable = $this
|
|
||||||
->getMockBuilder(PruneableCacheInterface::class)
|
|
||||||
->getMock();
|
|
||||||
|
|
||||||
$pruneable
|
|
||||||
->expects($this->atLeastOnce())
|
|
||||||
->method('prune')
|
|
||||||
->willReturn(false);
|
|
||||||
|
|
||||||
return $pruneable;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return MockObject|CacheInterface
|
|
||||||
*/
|
|
||||||
private function getNonPruneableMock()
|
|
||||||
{
|
|
||||||
return $this
|
|
||||||
->getMockBuilder(CacheInterface::class)
|
|
||||||
->getMock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface PruneableCacheInterface extends PruneableInterface, CacheInterface
|
|
||||||
{
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
<?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\Tests\Simple;
|
|
||||||
|
|
||||||
use Symfony\Component\Cache\Simple\DoctrineCache;
|
|
||||||
use Symfony\Component\Cache\Tests\Fixtures\ArrayCache;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @group time-sensitive
|
|
||||||
*/
|
|
||||||
class DoctrineCacheTest extends CacheTestCase
|
|
||||||
{
|
|
||||||
protected $skippedTests = [
|
|
||||||
'testObjectDoesNotChangeInCache' => 'ArrayCache does not use serialize/unserialize',
|
|
||||||
'testNotUnserializable' => 'ArrayCache does not use serialize/unserialize',
|
|
||||||
];
|
|
||||||
|
|
||||||
public function createSimpleCache($defaultLifetime = 0)
|
|
||||||
{
|
|
||||||
return new DoctrineCache(new ArrayCache($defaultLifetime), '', $defaultLifetime);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
<?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\Tests\Simple;
|
|
||||||
|
|
||||||
use Psr\SimpleCache\CacheInterface;
|
|
||||||
use Symfony\Component\Cache\Simple\FilesystemCache;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @group time-sensitive
|
|
||||||
*/
|
|
||||||
class FilesystemCacheTest extends CacheTestCase
|
|
||||||
{
|
|
||||||
public function createSimpleCache($defaultLifetime = 0)
|
|
||||||
{
|
|
||||||
return new FilesystemCache('', $defaultLifetime);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function isPruned(CacheInterface $cache, $name)
|
|
||||||
{
|
|
||||||
$getFileMethod = (new \ReflectionObject($cache))->getMethod('getFile');
|
|
||||||
$getFileMethod->setAccessible(true);
|
|
||||||
|
|
||||||
return !file_exists($getFileMethod->invoke($cache, $name));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,178 +0,0 @@
|
||||||
<?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\Tests\Simple;
|
|
||||||
|
|
||||||
use Symfony\Component\Cache\Adapter\AbstractAdapter;
|
|
||||||
use Symfony\Component\Cache\Simple\MemcachedCache;
|
|
||||||
|
|
||||||
class MemcachedCacheTest extends CacheTestCase
|
|
||||||
{
|
|
||||||
protected $skippedTests = [
|
|
||||||
'testSetTtl' => 'Testing expiration slows down the test suite',
|
|
||||||
'testSetMultipleTtl' => 'Testing expiration slows down the test suite',
|
|
||||||
'testDefaultLifeTime' => 'Testing expiration slows down the test suite',
|
|
||||||
];
|
|
||||||
|
|
||||||
protected static $client;
|
|
||||||
|
|
||||||
public static function setUpBeforeClass()
|
|
||||||
{
|
|
||||||
if (!MemcachedCache::isSupported()) {
|
|
||||||
self::markTestSkipped('Extension memcached >=2.2.0 required.');
|
|
||||||
}
|
|
||||||
self::$client = AbstractAdapter::createConnection('memcached://'.getenv('MEMCACHED_HOST'));
|
|
||||||
self::$client->get('foo');
|
|
||||||
$code = self::$client->getResultCode();
|
|
||||||
|
|
||||||
if (\Memcached::RES_SUCCESS !== $code && \Memcached::RES_NOTFOUND !== $code) {
|
|
||||||
self::markTestSkipped('Memcached error: '.strtolower(self::$client->getResultMessage()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function createSimpleCache($defaultLifetime = 0)
|
|
||||||
{
|
|
||||||
$client = $defaultLifetime ? AbstractAdapter::createConnection('memcached://'.getenv('MEMCACHED_HOST'), ['binary_protocol' => false]) : self::$client;
|
|
||||||
|
|
||||||
return new MemcachedCache($client, str_replace('\\', '.', __CLASS__), $defaultLifetime);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testCreatePersistentConnectionShouldNotDupServerList()
|
|
||||||
{
|
|
||||||
$instance = MemcachedCache::createConnection('memcached://'.getenv('MEMCACHED_HOST'), ['persistent_id' => 'persistent']);
|
|
||||||
$this->assertCount(1, $instance->getServerList());
|
|
||||||
|
|
||||||
$instance = MemcachedCache::createConnection('memcached://'.getenv('MEMCACHED_HOST'), ['persistent_id' => 'persistent']);
|
|
||||||
$this->assertCount(1, $instance->getServerList());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testOptions()
|
|
||||||
{
|
|
||||||
$client = MemcachedCache::createConnection([], [
|
|
||||||
'libketama_compatible' => false,
|
|
||||||
'distribution' => 'modula',
|
|
||||||
'compression' => true,
|
|
||||||
'serializer' => 'php',
|
|
||||||
'hash' => 'md5',
|
|
||||||
]);
|
|
||||||
|
|
||||||
$this->assertSame(\Memcached::SERIALIZER_PHP, $client->getOption(\Memcached::OPT_SERIALIZER));
|
|
||||||
$this->assertSame(\Memcached::HASH_MD5, $client->getOption(\Memcached::OPT_HASH));
|
|
||||||
$this->assertTrue($client->getOption(\Memcached::OPT_COMPRESSION));
|
|
||||||
$this->assertSame(0, $client->getOption(\Memcached::OPT_LIBKETAMA_COMPATIBLE));
|
|
||||||
$this->assertSame(\Memcached::DISTRIBUTION_MODULA, $client->getOption(\Memcached::OPT_DISTRIBUTION));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @dataProvider provideBadOptions
|
|
||||||
*/
|
|
||||||
public function testBadOptions($name, $value)
|
|
||||||
{
|
|
||||||
if (\PHP_VERSION_ID < 80000) {
|
|
||||||
$this->expectException('ErrorException');
|
|
||||||
$this->expectExceptionMessage('constant(): Couldn\'t find constant Memcached::');
|
|
||||||
} else {
|
|
||||||
$this->expectException('Error');
|
|
||||||
$this->expectExceptionMessage('Undefined constant Memcached::');
|
|
||||||
}
|
|
||||||
|
|
||||||
MemcachedCache::createConnection([], [$name => $value]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function provideBadOptions()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
['foo', 'bar'],
|
|
||||||
['hash', 'zyx'],
|
|
||||||
['serializer', 'zyx'],
|
|
||||||
['distribution', 'zyx'],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testDefaultOptions()
|
|
||||||
{
|
|
||||||
$this->assertTrue(MemcachedCache::isSupported());
|
|
||||||
|
|
||||||
$client = MemcachedCache::createConnection([]);
|
|
||||||
|
|
||||||
$this->assertTrue($client->getOption(\Memcached::OPT_COMPRESSION));
|
|
||||||
$this->assertSame(1, $client->getOption(\Memcached::OPT_BINARY_PROTOCOL));
|
|
||||||
$this->assertSame(1, $client->getOption(\Memcached::OPT_LIBKETAMA_COMPATIBLE));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testOptionSerializer()
|
|
||||||
{
|
|
||||||
$this->expectException('Symfony\Component\Cache\Exception\CacheException');
|
|
||||||
$this->expectExceptionMessage('MemcachedAdapter: "serializer" option must be "php" or "igbinary".');
|
|
||||||
if (!\Memcached::HAVE_JSON) {
|
|
||||||
$this->markTestSkipped('Memcached::HAVE_JSON required');
|
|
||||||
}
|
|
||||||
|
|
||||||
new MemcachedCache(MemcachedCache::createConnection([], ['serializer' => 'json']));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @dataProvider provideServersSetting
|
|
||||||
*/
|
|
||||||
public function testServersSetting($dsn, $host, $port)
|
|
||||||
{
|
|
||||||
$client1 = MemcachedCache::createConnection($dsn);
|
|
||||||
$client2 = MemcachedCache::createConnection([$dsn]);
|
|
||||||
$client3 = MemcachedCache::createConnection([[$host, $port]]);
|
|
||||||
$expect = [
|
|
||||||
'host' => $host,
|
|
||||||
'port' => $port,
|
|
||||||
];
|
|
||||||
|
|
||||||
$f = function ($s) { return ['host' => $s['host'], 'port' => $s['port']]; };
|
|
||||||
$this->assertSame([$expect], array_map($f, $client1->getServerList()));
|
|
||||||
$this->assertSame([$expect], array_map($f, $client2->getServerList()));
|
|
||||||
$this->assertSame([$expect], array_map($f, $client3->getServerList()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function provideServersSetting()
|
|
||||||
{
|
|
||||||
yield [
|
|
||||||
'memcached://127.0.0.1/50',
|
|
||||||
'127.0.0.1',
|
|
||||||
11211,
|
|
||||||
];
|
|
||||||
yield [
|
|
||||||
'memcached://localhost:11222?weight=25',
|
|
||||||
'localhost',
|
|
||||||
11222,
|
|
||||||
];
|
|
||||||
if (filter_var(ini_get('memcached.use_sasl'), \FILTER_VALIDATE_BOOLEAN)) {
|
|
||||||
yield [
|
|
||||||
'memcached://user:password@127.0.0.1?weight=50',
|
|
||||||
'127.0.0.1',
|
|
||||||
11211,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
yield [
|
|
||||||
'memcached:///var/run/memcached.sock?weight=25',
|
|
||||||
'/var/run/memcached.sock',
|
|
||||||
0,
|
|
||||||
];
|
|
||||||
yield [
|
|
||||||
'memcached:///var/local/run/memcached.socket?weight=25',
|
|
||||||
'/var/local/run/memcached.socket',
|
|
||||||
0,
|
|
||||||
];
|
|
||||||
if (filter_var(ini_get('memcached.use_sasl'), \FILTER_VALIDATE_BOOLEAN)) {
|
|
||||||
yield [
|
|
||||||
'memcached://user:password@/var/local/run/memcached.socket?weight=25',
|
|
||||||
'/var/local/run/memcached.socket',
|
|
||||||
0,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
<?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\Tests\Simple;
|
|
||||||
|
|
||||||
use Symfony\Component\Cache\Adapter\AbstractAdapter;
|
|
||||||
use Symfony\Component\Cache\Simple\MemcachedCache;
|
|
||||||
|
|
||||||
class MemcachedCacheTextModeTest extends MemcachedCacheTest
|
|
||||||
{
|
|
||||||
public function createSimpleCache($defaultLifetime = 0)
|
|
||||||
{
|
|
||||||
$client = AbstractAdapter::createConnection('memcached://'.getenv('MEMCACHED_HOST'), ['binary_protocol' => false]);
|
|
||||||
|
|
||||||
return new MemcachedCache($client, str_replace('\\', '.', __CLASS__), $defaultLifetime);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,96 +0,0 @@
|
||||||
<?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\Tests\Simple;
|
|
||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
|
||||||
use Symfony\Component\Cache\Simple\NullCache;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @group time-sensitive
|
|
||||||
*/
|
|
||||||
class NullCacheTest extends TestCase
|
|
||||||
{
|
|
||||||
public function createCachePool()
|
|
||||||
{
|
|
||||||
return new NullCache();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testGetItem()
|
|
||||||
{
|
|
||||||
$cache = $this->createCachePool();
|
|
||||||
|
|
||||||
$this->assertNull($cache->get('key'));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testHas()
|
|
||||||
{
|
|
||||||
$this->assertFalse($this->createCachePool()->has('key'));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testGetMultiple()
|
|
||||||
{
|
|
||||||
$cache = $this->createCachePool();
|
|
||||||
|
|
||||||
$keys = ['foo', 'bar', 'baz', 'biz'];
|
|
||||||
|
|
||||||
$default = new \stdClass();
|
|
||||||
$items = $cache->getMultiple($keys, $default);
|
|
||||||
$count = 0;
|
|
||||||
|
|
||||||
foreach ($items as $key => $item) {
|
|
||||||
$this->assertContains($key, $keys, 'Cache key can not change.');
|
|
||||||
$this->assertSame($default, $item);
|
|
||||||
|
|
||||||
// Remove $key for $keys
|
|
||||||
foreach ($keys as $k => $v) {
|
|
||||||
if ($v === $key) {
|
|
||||||
unset($keys[$k]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
++$count;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->assertSame(4, $count);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testClear()
|
|
||||||
{
|
|
||||||
$this->assertTrue($this->createCachePool()->clear());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testDelete()
|
|
||||||
{
|
|
||||||
$this->assertTrue($this->createCachePool()->delete('key'));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testDeleteMultiple()
|
|
||||||
{
|
|
||||||
$this->assertTrue($this->createCachePool()->deleteMultiple(['key', 'foo', 'bar']));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testSet()
|
|
||||||
{
|
|
||||||
$cache = $this->createCachePool();
|
|
||||||
|
|
||||||
$this->assertFalse($cache->set('key', 'val'));
|
|
||||||
$this->assertNull($cache->get('key'));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testSetMultiple()
|
|
||||||
{
|
|
||||||
$cache = $this->createCachePool();
|
|
||||||
|
|
||||||
$this->assertFalse($cache->setMultiple(['key' => 'val']));
|
|
||||||
$this->assertNull($cache->get('key'));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,47 +0,0 @@
|
||||||
<?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\Tests\Simple;
|
|
||||||
|
|
||||||
use Symfony\Component\Cache\Simple\PdoCache;
|
|
||||||
use Symfony\Component\Cache\Tests\Traits\PdoPruneableTrait;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @group time-sensitive
|
|
||||||
*/
|
|
||||||
class PdoCacheTest extends CacheTestCase
|
|
||||||
{
|
|
||||||
use PdoPruneableTrait;
|
|
||||||
|
|
||||||
protected static $dbFile;
|
|
||||||
|
|
||||||
public static function setUpBeforeClass()
|
|
||||||
{
|
|
||||||
if (!\extension_loaded('pdo_sqlite')) {
|
|
||||||
self::markTestSkipped('Extension pdo_sqlite required.');
|
|
||||||
}
|
|
||||||
|
|
||||||
self::$dbFile = tempnam(sys_get_temp_dir(), 'sf_sqlite_cache');
|
|
||||||
|
|
||||||
$pool = new PdoCache('sqlite:'.self::$dbFile);
|
|
||||||
$pool->createTable();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function tearDownAfterClass()
|
|
||||||
{
|
|
||||||
@unlink(self::$dbFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function createSimpleCache($defaultLifetime = 0)
|
|
||||||
{
|
|
||||||
return new PdoCache('sqlite:'.self::$dbFile, 'ns', $defaultLifetime);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,48 +0,0 @@
|
||||||
<?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\Tests\Simple;
|
|
||||||
|
|
||||||
use Doctrine\DBAL\DriverManager;
|
|
||||||
use Symfony\Component\Cache\Simple\PdoCache;
|
|
||||||
use Symfony\Component\Cache\Tests\Traits\PdoPruneableTrait;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @group time-sensitive
|
|
||||||
*/
|
|
||||||
class PdoDbalCacheTest extends CacheTestCase
|
|
||||||
{
|
|
||||||
use PdoPruneableTrait;
|
|
||||||
|
|
||||||
protected static $dbFile;
|
|
||||||
|
|
||||||
public static function setUpBeforeClass()
|
|
||||||
{
|
|
||||||
if (!\extension_loaded('pdo_sqlite')) {
|
|
||||||
self::markTestSkipped('Extension pdo_sqlite required.');
|
|
||||||
}
|
|
||||||
|
|
||||||
self::$dbFile = tempnam(sys_get_temp_dir(), 'sf_sqlite_cache');
|
|
||||||
|
|
||||||
$pool = new PdoCache(DriverManager::getConnection(['driver' => 'pdo_sqlite', 'path' => self::$dbFile]));
|
|
||||||
$pool->createTable();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function tearDownAfterClass()
|
|
||||||
{
|
|
||||||
@unlink(self::$dbFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function createSimpleCache($defaultLifetime = 0)
|
|
||||||
{
|
|
||||||
return new PdoCache(DriverManager::getConnection(['driver' => 'pdo_sqlite', 'path' => self::$dbFile]), '', $defaultLifetime);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,145 +0,0 @@
|
||||||
<?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\Tests\Simple;
|
|
||||||
|
|
||||||
use Symfony\Component\Cache\Simple\NullCache;
|
|
||||||
use Symfony\Component\Cache\Simple\PhpArrayCache;
|
|
||||||
use Symfony\Component\Cache\Tests\Adapter\FilesystemAdapterTest;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @group time-sensitive
|
|
||||||
*/
|
|
||||||
class PhpArrayCacheTest extends CacheTestCase
|
|
||||||
{
|
|
||||||
protected $skippedTests = [
|
|
||||||
'testBasicUsageWithLongKey' => 'PhpArrayCache does no writes',
|
|
||||||
|
|
||||||
'testDelete' => 'PhpArrayCache does no writes',
|
|
||||||
'testDeleteMultiple' => 'PhpArrayCache does no writes',
|
|
||||||
'testDeleteMultipleGenerator' => 'PhpArrayCache does no writes',
|
|
||||||
|
|
||||||
'testSetTtl' => 'PhpArrayCache does no expiration',
|
|
||||||
'testSetMultipleTtl' => 'PhpArrayCache does no expiration',
|
|
||||||
'testSetExpiredTtl' => 'PhpArrayCache does no expiration',
|
|
||||||
'testSetMultipleExpiredTtl' => 'PhpArrayCache does no expiration',
|
|
||||||
|
|
||||||
'testGetInvalidKeys' => 'PhpArrayCache does no validation',
|
|
||||||
'testGetMultipleInvalidKeys' => 'PhpArrayCache does no validation',
|
|
||||||
'testSetInvalidKeys' => 'PhpArrayCache does no validation',
|
|
||||||
'testDeleteInvalidKeys' => 'PhpArrayCache does no validation',
|
|
||||||
'testDeleteMultipleInvalidKeys' => 'PhpArrayCache does no validation',
|
|
||||||
'testSetInvalidTtl' => 'PhpArrayCache does no validation',
|
|
||||||
'testSetMultipleInvalidKeys' => 'PhpArrayCache does no validation',
|
|
||||||
'testSetMultipleInvalidTtl' => 'PhpArrayCache does no validation',
|
|
||||||
'testHasInvalidKeys' => 'PhpArrayCache does no validation',
|
|
||||||
'testSetValidData' => 'PhpArrayCache does no validation',
|
|
||||||
|
|
||||||
'testDefaultLifeTime' => 'PhpArrayCache does not allow configuring a default lifetime.',
|
|
||||||
'testPrune' => 'PhpArrayCache just proxies',
|
|
||||||
];
|
|
||||||
|
|
||||||
protected static $file;
|
|
||||||
|
|
||||||
public static function setUpBeforeClass()
|
|
||||||
{
|
|
||||||
self::$file = sys_get_temp_dir().'/symfony-cache/php-array-adapter-test.php';
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function tearDown()
|
|
||||||
{
|
|
||||||
$this->createSimpleCache()->clear();
|
|
||||||
|
|
||||||
if (file_exists(sys_get_temp_dir().'/symfony-cache')) {
|
|
||||||
FilesystemAdapterTest::rmdir(sys_get_temp_dir().'/symfony-cache');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function createSimpleCache()
|
|
||||||
{
|
|
||||||
return new PhpArrayCacheWrapper(self::$file, new NullCache());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testStore()
|
|
||||||
{
|
|
||||||
$arrayWithRefs = [];
|
|
||||||
$arrayWithRefs[0] = 123;
|
|
||||||
$arrayWithRefs[1] = &$arrayWithRefs[0];
|
|
||||||
|
|
||||||
$object = (object) [
|
|
||||||
'foo' => 'bar',
|
|
||||||
'foo2' => 'bar2',
|
|
||||||
];
|
|
||||||
|
|
||||||
$expected = [
|
|
||||||
'null' => null,
|
|
||||||
'serializedString' => serialize($object),
|
|
||||||
'arrayWithRefs' => $arrayWithRefs,
|
|
||||||
'object' => $object,
|
|
||||||
'arrayWithObject' => ['bar' => $object],
|
|
||||||
];
|
|
||||||
|
|
||||||
$cache = new PhpArrayCache(self::$file, new NullCache());
|
|
||||||
$cache->warmUp($expected);
|
|
||||||
|
|
||||||
foreach ($expected as $key => $value) {
|
|
||||||
$this->assertSame(serialize($value), serialize($cache->get($key)), 'Warm up should create a PHP file that OPCache can load in memory');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testStoredFile()
|
|
||||||
{
|
|
||||||
$expected = [
|
|
||||||
'integer' => 42,
|
|
||||||
'float' => 42.42,
|
|
||||||
'boolean' => true,
|
|
||||||
'array_simple' => ['foo', 'bar'],
|
|
||||||
'array_associative' => ['foo' => 'bar', 'foo2' => 'bar2'],
|
|
||||||
];
|
|
||||||
|
|
||||||
$cache = new PhpArrayCache(self::$file, new NullCache());
|
|
||||||
$cache->warmUp($expected);
|
|
||||||
|
|
||||||
$values = eval(substr(file_get_contents(self::$file), 6));
|
|
||||||
|
|
||||||
$this->assertSame($expected, $values, 'Warm up should create a PHP file that OPCache can load in memory');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class PhpArrayCacheWrapper extends PhpArrayCache
|
|
||||||
{
|
|
||||||
public function set($key, $value, $ttl = null)
|
|
||||||
{
|
|
||||||
\call_user_func(\Closure::bind(function () use ($key, $value) {
|
|
||||||
$this->values[$key] = $value;
|
|
||||||
$this->warmUp($this->values);
|
|
||||||
$this->values = eval(substr(file_get_contents($this->file), 6));
|
|
||||||
}, $this, PhpArrayCache::class));
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setMultiple($values, $ttl = null)
|
|
||||||
{
|
|
||||||
if (!\is_array($values) && !$values instanceof \Traversable) {
|
|
||||||
return parent::setMultiple($values, $ttl);
|
|
||||||
}
|
|
||||||
\call_user_func(\Closure::bind(function () use ($values) {
|
|
||||||
foreach ($values as $key => $value) {
|
|
||||||
$this->values[$key] = $value;
|
|
||||||
}
|
|
||||||
$this->warmUp($this->values);
|
|
||||||
$this->values = eval(substr(file_get_contents($this->file), 6));
|
|
||||||
}, $this, PhpArrayCache::class));
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,57 +0,0 @@
|
||||||
<?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\Tests\Simple;
|
|
||||||
|
|
||||||
use Symfony\Component\Cache\Simple\FilesystemCache;
|
|
||||||
use Symfony\Component\Cache\Simple\PhpArrayCache;
|
|
||||||
use Symfony\Component\Cache\Tests\Adapter\FilesystemAdapterTest;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @group time-sensitive
|
|
||||||
*/
|
|
||||||
class PhpArrayCacheWithFallbackTest extends CacheTestCase
|
|
||||||
{
|
|
||||||
protected $skippedTests = [
|
|
||||||
'testGetInvalidKeys' => 'PhpArrayCache does no validation',
|
|
||||||
'testGetMultipleInvalidKeys' => 'PhpArrayCache does no validation',
|
|
||||||
'testDeleteInvalidKeys' => 'PhpArrayCache does no validation',
|
|
||||||
'testDeleteMultipleInvalidKeys' => 'PhpArrayCache does no validation',
|
|
||||||
//'testSetValidData' => 'PhpArrayCache does no validation',
|
|
||||||
'testSetInvalidKeys' => 'PhpArrayCache does no validation',
|
|
||||||
'testSetInvalidTtl' => 'PhpArrayCache does no validation',
|
|
||||||
'testSetMultipleInvalidKeys' => 'PhpArrayCache does no validation',
|
|
||||||
'testSetMultipleInvalidTtl' => 'PhpArrayCache does no validation',
|
|
||||||
'testHasInvalidKeys' => 'PhpArrayCache does no validation',
|
|
||||||
'testPrune' => 'PhpArrayCache just proxies',
|
|
||||||
];
|
|
||||||
|
|
||||||
protected static $file;
|
|
||||||
|
|
||||||
public static function setUpBeforeClass()
|
|
||||||
{
|
|
||||||
self::$file = sys_get_temp_dir().'/symfony-cache/php-array-adapter-test.php';
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function tearDown()
|
|
||||||
{
|
|
||||||
$this->createSimpleCache()->clear();
|
|
||||||
|
|
||||||
if (file_exists(sys_get_temp_dir().'/symfony-cache')) {
|
|
||||||
FilesystemAdapterTest::rmdir(sys_get_temp_dir().'/symfony-cache');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function createSimpleCache($defaultLifetime = 0)
|
|
||||||
{
|
|
||||||
return new PhpArrayCache(self::$file, new FilesystemCache('php-array-fallback', $defaultLifetime));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,42 +0,0 @@
|
||||||
<?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\Tests\Simple;
|
|
||||||
|
|
||||||
use Psr\SimpleCache\CacheInterface;
|
|
||||||
use Symfony\Component\Cache\Simple\PhpFilesCache;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @group time-sensitive
|
|
||||||
*/
|
|
||||||
class PhpFilesCacheTest extends CacheTestCase
|
|
||||||
{
|
|
||||||
protected $skippedTests = [
|
|
||||||
'testDefaultLifeTime' => 'PhpFilesCache does not allow configuring a default lifetime.',
|
|
||||||
];
|
|
||||||
|
|
||||||
public function createSimpleCache()
|
|
||||||
{
|
|
||||||
if (!PhpFilesCache::isSupported()) {
|
|
||||||
$this->markTestSkipped('OPcache extension is not enabled.');
|
|
||||||
}
|
|
||||||
|
|
||||||
return new PhpFilesCache('sf-cache');
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function isPruned(CacheInterface $cache, $name)
|
|
||||||
{
|
|
||||||
$getFileMethod = (new \ReflectionObject($cache))->getMethod('getFile');
|
|
||||||
$getFileMethod->setAccessible(true);
|
|
||||||
|
|
||||||
return !file_exists($getFileMethod->invoke($cache, $name));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
<?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\Tests\Simple;
|
|
||||||
|
|
||||||
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
|
|
||||||
use Symfony\Component\Cache\Simple\Psr6Cache;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @group time-sensitive
|
|
||||||
*/
|
|
||||||
class Psr6CacheTest extends CacheTestCase
|
|
||||||
{
|
|
||||||
protected $skippedTests = [
|
|
||||||
'testPrune' => 'Psr6Cache just proxies',
|
|
||||||
];
|
|
||||||
|
|
||||||
public function createSimpleCache($defaultLifetime = 0)
|
|
||||||
{
|
|
||||||
return new Psr6Cache(new FilesystemAdapter('', $defaultLifetime));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
<?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\Tests\Simple;
|
|
||||||
|
|
||||||
class RedisArrayCacheTest extends AbstractRedisCacheTest
|
|
||||||
{
|
|
||||||
public static function setUpBeforeClass()
|
|
||||||
{
|
|
||||||
parent::setupBeforeClass();
|
|
||||||
if (!class_exists('RedisArray')) {
|
|
||||||
self::markTestSkipped('The RedisArray class is required.');
|
|
||||||
}
|
|
||||||
self::$redis = new \RedisArray([getenv('REDIS_HOST')], ['lazy_connect' => true]);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,82 +0,0 @@
|
||||||
<?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\Tests\Simple;
|
|
||||||
|
|
||||||
use Symfony\Component\Cache\Simple\RedisCache;
|
|
||||||
|
|
||||||
class RedisCacheTest extends AbstractRedisCacheTest
|
|
||||||
{
|
|
||||||
public static function setUpBeforeClass()
|
|
||||||
{
|
|
||||||
parent::setupBeforeClass();
|
|
||||||
self::$redis = RedisCache::createConnection('redis://'.getenv('REDIS_HOST'));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testCreateConnection()
|
|
||||||
{
|
|
||||||
$redisHost = getenv('REDIS_HOST');
|
|
||||||
|
|
||||||
$redis = RedisCache::createConnection('redis://'.$redisHost);
|
|
||||||
$this->assertInstanceOf(\Redis::class, $redis);
|
|
||||||
$this->assertTrue($redis->isConnected());
|
|
||||||
$this->assertSame(0, $redis->getDbNum());
|
|
||||||
|
|
||||||
$redis = RedisCache::createConnection('redis://'.$redisHost.'/2');
|
|
||||||
$this->assertSame(2, $redis->getDbNum());
|
|
||||||
|
|
||||||
$redis = RedisCache::createConnection('redis://'.$redisHost, ['timeout' => 3]);
|
|
||||||
$this->assertEquals(3, $redis->getTimeout());
|
|
||||||
|
|
||||||
$redis = RedisCache::createConnection('redis://'.$redisHost.'?timeout=4');
|
|
||||||
$this->assertEquals(4, $redis->getTimeout());
|
|
||||||
|
|
||||||
$redis = RedisCache::createConnection('redis://'.$redisHost, ['read_timeout' => 5]);
|
|
||||||
$this->assertEquals(5, $redis->getReadTimeout());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @dataProvider provideFailedCreateConnection
|
|
||||||
*/
|
|
||||||
public function testFailedCreateConnection($dsn)
|
|
||||||
{
|
|
||||||
$this->expectException('Symfony\Component\Cache\Exception\InvalidArgumentException');
|
|
||||||
$this->expectExceptionMessage('Redis connection ');
|
|
||||||
RedisCache::createConnection($dsn);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function provideFailedCreateConnection()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
['redis://localhost:1234'],
|
|
||||||
['redis://foo@localhost'],
|
|
||||||
['redis://localhost/123'],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @dataProvider provideInvalidCreateConnection
|
|
||||||
*/
|
|
||||||
public function testInvalidCreateConnection($dsn)
|
|
||||||
{
|
|
||||||
$this->expectException('Symfony\Component\Cache\Exception\InvalidArgumentException');
|
|
||||||
$this->expectExceptionMessage('Invalid Redis DSN');
|
|
||||||
RedisCache::createConnection($dsn);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function provideInvalidCreateConnection()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
['foo://localhost'],
|
|
||||||
['redis://'],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
<?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\Tests\Simple;
|
|
||||||
|
|
||||||
class RedisClusterCacheTest extends AbstractRedisCacheTest
|
|
||||||
{
|
|
||||||
public static function setUpBeforeClass()
|
|
||||||
{
|
|
||||||
if (!class_exists('RedisCluster')) {
|
|
||||||
self::markTestSkipped('The RedisCluster class is required.');
|
|
||||||
}
|
|
||||||
if (!$hosts = getenv('REDIS_CLUSTER_HOSTS')) {
|
|
||||||
self::markTestSkipped('REDIS_CLUSTER_HOSTS env var is not defined.');
|
|
||||||
}
|
|
||||||
|
|
||||||
self::$redis = new \RedisCluster(null, explode(' ', $hosts));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,171 +0,0 @@
|
||||||
<?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\Tests\Simple;
|
|
||||||
|
|
||||||
use Symfony\Component\Cache\Simple\FilesystemCache;
|
|
||||||
use Symfony\Component\Cache\Simple\TraceableCache;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @group time-sensitive
|
|
||||||
*/
|
|
||||||
class TraceableCacheTest extends CacheTestCase
|
|
||||||
{
|
|
||||||
protected $skippedTests = [
|
|
||||||
'testPrune' => 'TraceableCache just proxies',
|
|
||||||
];
|
|
||||||
|
|
||||||
public function createSimpleCache($defaultLifetime = 0)
|
|
||||||
{
|
|
||||||
return new TraceableCache(new FilesystemCache('', $defaultLifetime));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testGetMissTrace()
|
|
||||||
{
|
|
||||||
$pool = $this->createSimpleCache();
|
|
||||||
$pool->get('k');
|
|
||||||
$calls = $pool->getCalls();
|
|
||||||
$this->assertCount(1, $calls);
|
|
||||||
|
|
||||||
$call = $calls[0];
|
|
||||||
$this->assertSame('get', $call->name);
|
|
||||||
$this->assertSame(['k' => false], $call->result);
|
|
||||||
$this->assertSame(0, $call->hits);
|
|
||||||
$this->assertSame(1, $call->misses);
|
|
||||||
$this->assertNotEmpty($call->start);
|
|
||||||
$this->assertNotEmpty($call->end);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testGetHitTrace()
|
|
||||||
{
|
|
||||||
$pool = $this->createSimpleCache();
|
|
||||||
$pool->set('k', 'foo');
|
|
||||||
$pool->get('k');
|
|
||||||
$calls = $pool->getCalls();
|
|
||||||
$this->assertCount(2, $calls);
|
|
||||||
|
|
||||||
$call = $calls[1];
|
|
||||||
$this->assertSame(1, $call->hits);
|
|
||||||
$this->assertSame(0, $call->misses);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testGetMultipleMissTrace()
|
|
||||||
{
|
|
||||||
$pool = $this->createSimpleCache();
|
|
||||||
$pool->set('k1', 123);
|
|
||||||
$values = $pool->getMultiple(['k0', 'k1']);
|
|
||||||
foreach ($values as $value) {
|
|
||||||
}
|
|
||||||
$calls = $pool->getCalls();
|
|
||||||
$this->assertCount(2, $calls);
|
|
||||||
|
|
||||||
$call = $calls[1];
|
|
||||||
$this->assertSame('getMultiple', $call->name);
|
|
||||||
$this->assertSame(['k1' => true, 'k0' => false], $call->result);
|
|
||||||
$this->assertSame(1, $call->misses);
|
|
||||||
$this->assertNotEmpty($call->start);
|
|
||||||
$this->assertNotEmpty($call->end);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testHasMissTrace()
|
|
||||||
{
|
|
||||||
$pool = $this->createSimpleCache();
|
|
||||||
$pool->has('k');
|
|
||||||
$calls = $pool->getCalls();
|
|
||||||
$this->assertCount(1, $calls);
|
|
||||||
|
|
||||||
$call = $calls[0];
|
|
||||||
$this->assertSame('has', $call->name);
|
|
||||||
$this->assertSame(['k' => false], $call->result);
|
|
||||||
$this->assertNotEmpty($call->start);
|
|
||||||
$this->assertNotEmpty($call->end);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testHasHitTrace()
|
|
||||||
{
|
|
||||||
$pool = $this->createSimpleCache();
|
|
||||||
$pool->set('k', 'foo');
|
|
||||||
$pool->has('k');
|
|
||||||
$calls = $pool->getCalls();
|
|
||||||
$this->assertCount(2, $calls);
|
|
||||||
|
|
||||||
$call = $calls[1];
|
|
||||||
$this->assertSame('has', $call->name);
|
|
||||||
$this->assertSame(['k' => true], $call->result);
|
|
||||||
$this->assertNotEmpty($call->start);
|
|
||||||
$this->assertNotEmpty($call->end);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testDeleteTrace()
|
|
||||||
{
|
|
||||||
$pool = $this->createSimpleCache();
|
|
||||||
$pool->delete('k');
|
|
||||||
$calls = $pool->getCalls();
|
|
||||||
$this->assertCount(1, $calls);
|
|
||||||
|
|
||||||
$call = $calls[0];
|
|
||||||
$this->assertSame('delete', $call->name);
|
|
||||||
$this->assertSame(['k' => true], $call->result);
|
|
||||||
$this->assertSame(0, $call->hits);
|
|
||||||
$this->assertSame(0, $call->misses);
|
|
||||||
$this->assertNotEmpty($call->start);
|
|
||||||
$this->assertNotEmpty($call->end);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testDeleteMultipleTrace()
|
|
||||||
{
|
|
||||||
$pool = $this->createSimpleCache();
|
|
||||||
$arg = ['k0', 'k1'];
|
|
||||||
$pool->deleteMultiple($arg);
|
|
||||||
$calls = $pool->getCalls();
|
|
||||||
$this->assertCount(1, $calls);
|
|
||||||
|
|
||||||
$call = $calls[0];
|
|
||||||
$this->assertSame('deleteMultiple', $call->name);
|
|
||||||
$this->assertSame(['keys' => $arg, 'result' => true], $call->result);
|
|
||||||
$this->assertSame(0, $call->hits);
|
|
||||||
$this->assertSame(0, $call->misses);
|
|
||||||
$this->assertNotEmpty($call->start);
|
|
||||||
$this->assertNotEmpty($call->end);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testTraceSetTrace()
|
|
||||||
{
|
|
||||||
$pool = $this->createSimpleCache();
|
|
||||||
$pool->set('k', 'foo');
|
|
||||||
$calls = $pool->getCalls();
|
|
||||||
$this->assertCount(1, $calls);
|
|
||||||
|
|
||||||
$call = $calls[0];
|
|
||||||
$this->assertSame('set', $call->name);
|
|
||||||
$this->assertSame(['k' => true], $call->result);
|
|
||||||
$this->assertSame(0, $call->hits);
|
|
||||||
$this->assertSame(0, $call->misses);
|
|
||||||
$this->assertNotEmpty($call->start);
|
|
||||||
$this->assertNotEmpty($call->end);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testSetMultipleTrace()
|
|
||||||
{
|
|
||||||
$pool = $this->createSimpleCache();
|
|
||||||
$pool->setMultiple(['k' => 'foo']);
|
|
||||||
$calls = $pool->getCalls();
|
|
||||||
$this->assertCount(1, $calls);
|
|
||||||
|
|
||||||
$call = $calls[0];
|
|
||||||
$this->assertSame('setMultiple', $call->name);
|
|
||||||
$this->assertSame(['keys' => ['k'], 'result' => true], $call->result);
|
|
||||||
$this->assertSame(0, $call->hits);
|
|
||||||
$this->assertSame(0, $call->misses);
|
|
||||||
$this->assertNotEmpty($call->start);
|
|
||||||
$this->assertNotEmpty($call->end);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
<?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\Tests\Traits;
|
|
||||||
|
|
||||||
trait PdoPruneableTrait
|
|
||||||
{
|
|
||||||
protected function isPruned($cache, $name)
|
|
||||||
{
|
|
||||||
$o = new \ReflectionObject($cache);
|
|
||||||
|
|
||||||
if (!$o->hasMethod('getConnection')) {
|
|
||||||
self::fail('Cache does not have "getConnection()" method.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$getPdoConn = $o->getMethod('getConnection');
|
|
||||||
$getPdoConn->setAccessible(true);
|
|
||||||
|
|
||||||
/** @var \Doctrine\DBAL\Statement|\PDOStatement $select */
|
|
||||||
$select = $getPdoConn->invoke($cache)->prepare('SELECT 1 FROM cache_items WHERE item_id LIKE :id');
|
|
||||||
$select->bindValue(':id', sprintf('%%%s', $name));
|
|
||||||
$result = $select->execute();
|
|
||||||
|
|
||||||
return 1 !== (int) (\is_object($result) ? $result->fetchOne() : $select->fetch(\PDO::FETCH_COLUMN));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,50 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
|
|
||||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/5.2/phpunit.xsd"
|
|
||||||
backupGlobals="false"
|
|
||||||
colors="true"
|
|
||||||
bootstrap="vendor/autoload.php"
|
|
||||||
failOnRisky="true"
|
|
||||||
failOnWarning="true"
|
|
||||||
>
|
|
||||||
<php>
|
|
||||||
<ini name="error_reporting" value="-1" />
|
|
||||||
<env name="REDIS_HOST" value="localhost" />
|
|
||||||
<env name="MEMCACHED_HOST" value="localhost" />
|
|
||||||
</php>
|
|
||||||
|
|
||||||
<testsuites>
|
|
||||||
<testsuite name="Symfony Cache Component Test Suite">
|
|
||||||
<directory>./Tests/</directory>
|
|
||||||
</testsuite>
|
|
||||||
</testsuites>
|
|
||||||
|
|
||||||
<filter>
|
|
||||||
<whitelist>
|
|
||||||
<directory>./</directory>
|
|
||||||
<exclude>
|
|
||||||
<directory>./Tests</directory>
|
|
||||||
<directory>./vendor</directory>
|
|
||||||
</exclude>
|
|
||||||
</whitelist>
|
|
||||||
</filter>
|
|
||||||
|
|
||||||
<listeners>
|
|
||||||
<listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener">
|
|
||||||
<arguments>
|
|
||||||
<array>
|
|
||||||
<element key="time-sensitive">
|
|
||||||
<array>
|
|
||||||
<element key="0"><string>Cache\IntegrationTests</string></element>
|
|
||||||
<element key="1"><string>Doctrine\Common\Cache</string></element>
|
|
||||||
<element key="2"><string>Symfony\Component\Cache</string></element>
|
|
||||||
<element key="3"><string>Symfony\Component\Cache\Tests\Fixtures</string></element>
|
|
||||||
<element key="4"><string>Symfony\Component\Cache\Traits</string></element>
|
|
||||||
</array>
|
|
||||||
</element>
|
|
||||||
</array>
|
|
||||||
</arguments>
|
|
||||||
</listener>
|
|
||||||
</listeners>
|
|
||||||
</phpunit>
|
|
|
@ -1,106 +0,0 @@
|
||||||
<?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\Polyfill\Apcu;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Apcu for Zend Server Data Cache.
|
|
||||||
*
|
|
||||||
* @author Kate Gray <opensource@codebykate.com>
|
|
||||||
* @author Nicolas Grekas <p@tchwork.com>
|
|
||||||
*
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
final class Apcu
|
|
||||||
{
|
|
||||||
public static function apcu_add($key, $var = null, $ttl = 0)
|
|
||||||
{
|
|
||||||
if (!\is_array($key)) {
|
|
||||||
return apc_add($key, $var, $ttl);
|
|
||||||
}
|
|
||||||
|
|
||||||
$errors = [];
|
|
||||||
foreach ($key as $k => $v) {
|
|
||||||
if (!apc_add($k, $v, $ttl)) {
|
|
||||||
$errors[$k] = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $errors;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function apcu_store($key, $var = null, $ttl = 0)
|
|
||||||
{
|
|
||||||
if (!\is_array($key)) {
|
|
||||||
return apc_store($key, $var, $ttl);
|
|
||||||
}
|
|
||||||
|
|
||||||
$errors = [];
|
|
||||||
foreach ($key as $k => $v) {
|
|
||||||
if (!apc_store($k, $v, $ttl)) {
|
|
||||||
$errors[$k] = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $errors;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function apcu_exists($keys)
|
|
||||||
{
|
|
||||||
if (!\is_array($keys)) {
|
|
||||||
return apc_exists($keys);
|
|
||||||
}
|
|
||||||
|
|
||||||
$existing = [];
|
|
||||||
foreach ($keys as $k) {
|
|
||||||
if (apc_exists($k)) {
|
|
||||||
$existing[$k] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $existing;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function apcu_fetch($key, &$success = null)
|
|
||||||
{
|
|
||||||
if (!\is_array($key)) {
|
|
||||||
return apc_fetch($key, $success);
|
|
||||||
}
|
|
||||||
|
|
||||||
$succeeded = true;
|
|
||||||
$values = [];
|
|
||||||
foreach ($key as $k) {
|
|
||||||
$v = apc_fetch($k, $success);
|
|
||||||
if ($success) {
|
|
||||||
$values[$k] = $v;
|
|
||||||
} else {
|
|
||||||
$succeeded = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$success = $succeeded;
|
|
||||||
|
|
||||||
return $values;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function apcu_delete($key)
|
|
||||||
{
|
|
||||||
if (!\is_array($key)) {
|
|
||||||
return apc_delete($key);
|
|
||||||
}
|
|
||||||
|
|
||||||
$success = true;
|
|
||||||
foreach ($key as $k) {
|
|
||||||
$success = apc_delete($k) && $success;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $success;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
Copyright (c) 2015-present Fabien Potencier
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
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.
|
|
|
@ -1,12 +0,0 @@
|
||||||
Symfony Polyfill / APCu
|
|
||||||
========================
|
|
||||||
|
|
||||||
This component provides `apcu_*` functions and the `APCuIterator` class to users of the legacy APC extension.
|
|
||||||
|
|
||||||
More information can be found in the
|
|
||||||
[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md).
|
|
||||||
|
|
||||||
License
|
|
||||||
=======
|
|
||||||
|
|
||||||
This library is released under the [MIT license](LICENSE).
|
|
|
@ -1,83 +0,0 @@
|
||||||
<?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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use Symfony\Polyfill\Apcu as p;
|
|
||||||
|
|
||||||
if (!extension_loaded('apc') && !extension_loaded('apcu')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (\PHP_VERSION_ID >= 80000) {
|
|
||||||
return require __DIR__.'/bootstrap80.php';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (extension_loaded('Zend Data Cache')) {
|
|
||||||
if (!function_exists('apcu_add')) {
|
|
||||||
function apcu_add($key, $value = null, $ttl = 0) { return p\Apcu::apcu_add($key, $value, $ttl); }
|
|
||||||
}
|
|
||||||
if (!function_exists('apcu_delete')) {
|
|
||||||
function apcu_delete($key) { return p\Apcu::apcu_delete($key); }
|
|
||||||
}
|
|
||||||
if (!function_exists('apcu_exists')) {
|
|
||||||
function apcu_exists($key) { return p\Apcu::apcu_exists($key); }
|
|
||||||
}
|
|
||||||
if (!function_exists('apcu_fetch')) {
|
|
||||||
function apcu_fetch($key, &$success = null) { return p\Apcu::apcu_fetch($key, $success); }
|
|
||||||
}
|
|
||||||
if (!function_exists('apcu_store')) {
|
|
||||||
function apcu_store($key, $value = null, $ttl = 0) { return p\Apcu::apcu_store($key, $value, $ttl); }
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!function_exists('apcu_add')) {
|
|
||||||
function apcu_add($key, $value = null, $ttl = 0) { return apc_add($key, $value, $ttl); }
|
|
||||||
}
|
|
||||||
if (!function_exists('apcu_delete')) {
|
|
||||||
function apcu_delete($key) { return apc_delete($key); }
|
|
||||||
}
|
|
||||||
if (!function_exists('apcu_exists')) {
|
|
||||||
function apcu_exists($key) { return apc_exists($key); }
|
|
||||||
}
|
|
||||||
if (!function_exists('apcu_fetch')) {
|
|
||||||
function apcu_fetch($key, &$success = null) { return apc_fetch($key, $success); }
|
|
||||||
}
|
|
||||||
if (!function_exists('apcu_store')) {
|
|
||||||
function apcu_store($key, $value = null, $ttl = 0) { return apc_store($key, $value, $ttl); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!function_exists('apcu_cache_info')) {
|
|
||||||
function apcu_cache_info($limited = false) { return apc_cache_info('user', $limited); }
|
|
||||||
}
|
|
||||||
if (!function_exists('apcu_cas')) {
|
|
||||||
function apcu_cas($key, $old, $new) { return apc_cas($key, $old, $new); }
|
|
||||||
}
|
|
||||||
if (!function_exists('apcu_clear_cache')) {
|
|
||||||
function apcu_clear_cache() { return apc_clear_cache('user'); }
|
|
||||||
}
|
|
||||||
if (!function_exists('apcu_dec')) {
|
|
||||||
function apcu_dec($key, $step = 1, &$success = false) { return apc_dec($key, $step, $success); }
|
|
||||||
}
|
|
||||||
if (!function_exists('apcu_inc')) {
|
|
||||||
function apcu_inc($key, $step = 1, &$success = false) { return apc_inc($key, $step, $success); }
|
|
||||||
}
|
|
||||||
if (!function_exists('apcu_sma_info')) {
|
|
||||||
function apcu_sma_info($limited = false) { return apc_sma_info($limited); }
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!class_exists('APCuIterator', false) && class_exists('APCIterator', false)) {
|
|
||||||
class APCuIterator extends APCIterator
|
|
||||||
{
|
|
||||||
public function __construct($search = null, $format = \APC_ITER_ALL, $chunk_size = 100, $list = \APC_LIST_ACTIVE)
|
|
||||||
{
|
|
||||||
parent::__construct('user', $search, $format, $chunk_size, $list);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,75 +0,0 @@
|
||||||
<?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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use Symfony\Polyfill\Apcu as p;
|
|
||||||
|
|
||||||
if (extension_loaded('Zend Data Cache')) {
|
|
||||||
if (!function_exists('apcu_add')) {
|
|
||||||
function apcu_add($key, mixed $value, ?int $ttl = 0): array|bool { return p\Apcu::apcu_add($key, $value, (int) $ttl); }
|
|
||||||
}
|
|
||||||
if (!function_exists('apcu_delete')) {
|
|
||||||
function apcu_delete($key): array|bool { return p\Apcu::apcu_delete($key); }
|
|
||||||
}
|
|
||||||
if (!function_exists('apcu_exists')) {
|
|
||||||
function apcu_exists($key): array|bool { return p\Apcu::apcu_exists($key); }
|
|
||||||
}
|
|
||||||
if (!function_exists('apcu_fetch')) {
|
|
||||||
function apcu_fetch($key, &$success = null): mixed { return p\Apcu::apcu_fetch($key, $success); }
|
|
||||||
}
|
|
||||||
if (!function_exists('apcu_store')) {
|
|
||||||
function apcu_store($key, mixed $value, ?int $ttl = 0): array|bool { return p\Apcu::apcu_store($key, $value, (int) $ttl); }
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!function_exists('apcu_add')) {
|
|
||||||
function apcu_add($key, mixed $value, ?int $ttl = 0): array|bool { return apc_add($key, $value, (int) $ttl); }
|
|
||||||
}
|
|
||||||
if (!function_exists('apcu_delete')) {
|
|
||||||
function apcu_delete($key): array|bool { return apc_delete($key); }
|
|
||||||
}
|
|
||||||
if (!function_exists('apcu_exists')) {
|
|
||||||
function apcu_exists($key): array|bool { return apc_exists($key); }
|
|
||||||
}
|
|
||||||
if (!function_exists('apcu_fetch')) {
|
|
||||||
function apcu_fetch($key, &$success = null) { return apc_fetch($key, $success); }
|
|
||||||
}
|
|
||||||
if (!function_exists('apcu_store')) {
|
|
||||||
function apcu_store($key, mixed $value, ?int $ttl = 0): array|bool { return apc_store($key, $value, (int) $ttl); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!function_exists('apcu_cache_info')) {
|
|
||||||
function apcu_cache_info($limited = false) { return apc_cache_info('user', $limited); }
|
|
||||||
}
|
|
||||||
if (!function_exists('apcu_cas')) {
|
|
||||||
function apcu_cas($key, $old, $new) { return apc_cas($key, $old, $new); }
|
|
||||||
}
|
|
||||||
if (!function_exists('apcu_clear_cache')) {
|
|
||||||
function apcu_clear_cache() { return apc_clear_cache('user'); }
|
|
||||||
}
|
|
||||||
if (!function_exists('apcu_dec')) {
|
|
||||||
function apcu_dec($key, $step = 1, &$success = false) { return apc_dec($key, $step, $success); }
|
|
||||||
}
|
|
||||||
if (!function_exists('apcu_inc')) {
|
|
||||||
function apcu_inc($key, $step = 1, &$success = false) { return apc_inc($key, $step, $success); }
|
|
||||||
}
|
|
||||||
if (!function_exists('apcu_sma_info')) {
|
|
||||||
function apcu_sma_info($limited = false) { return apc_sma_info($limited); }
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!class_exists('APCuIterator', false) && class_exists('APCIterator', false)) {
|
|
||||||
class APCuIterator extends APCIterator
|
|
||||||
{
|
|
||||||
public function __construct($search = null, $format = APC_ITER_ALL, $chunk_size = 100, $list = APC_LIST_ACTIVE)
|
|
||||||
{
|
|
||||||
parent::__construct('user', $search, $format, $chunk_size, $list);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
{
|
|
||||||
"name": "symfony/polyfill-apcu",
|
|
||||||
"type": "library",
|
|
||||||
"description": "Symfony polyfill backporting apcu_* functions to lower PHP versions",
|
|
||||||
"keywords": ["polyfill", "shim", "compatibility", "portable", "apcu"],
|
|
||||||
"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.1"
|
|
||||||
},
|
|
||||||
"autoload": {
|
|
||||||
"psr-4": { "Symfony\\Polyfill\\Apcu\\": "" },
|
|
||||||
"files": [ "bootstrap.php" ]
|
|
||||||
},
|
|
||||||
"minimum-stability": "dev",
|
|
||||||
"extra": {
|
|
||||||
"branch-alias": {
|
|
||||||
"dev-main": "1.28-dev"
|
|
||||||
},
|
|
||||||
"thanks": {
|
|
||||||
"name": "symfony/polyfill",
|
|
||||||
"url": "https://github.com/symfony/polyfill"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -15,6 +15,7 @@ use Friendica\Core\Logger;
|
||||||
use Friendica\Core\Renderer;
|
use Friendica\Core\Renderer;
|
||||||
use Friendica\Core\System;
|
use Friendica\Core\System;
|
||||||
use Friendica\Network\HTTPException\ForbiddenException;
|
use Friendica\Network\HTTPException\ForbiddenException;
|
||||||
|
use Friendica\Util\HTTPSignature;
|
||||||
use Friendica\Util\Network;
|
use Friendica\Util\Network;
|
||||||
|
|
||||||
require_once __DIR__ . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php';
|
require_once __DIR__ . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php';
|
||||||
|
@ -76,6 +77,8 @@ function blockbot_init_1()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
blockbot_log_activitypub($_SERVER['REQUEST_URI'], $_SERVER['HTTP_USER_AGENT']);
|
||||||
|
|
||||||
if (blockbot_is_crawler($parts)) {
|
if (blockbot_is_crawler($parts)) {
|
||||||
Logger::debug('Crawler found - reject', $logdata);
|
Logger::debug('Crawler found - reject', $logdata);
|
||||||
blockbot_reject();
|
blockbot_reject();
|
||||||
|
@ -169,7 +172,7 @@ function blockbot_init_1()
|
||||||
|
|
||||||
function blockbot_save($database, $userAgent)
|
function blockbot_save($database, $userAgent)
|
||||||
{
|
{
|
||||||
if (!DI::config()->get('blockbot', 'training') || !function_exists('dba_open')) {
|
if (!DI::config()->get('blockbot', 'logging') || !function_exists('dba_open')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,6 +184,36 @@ function blockbot_save($database, $userAgent)
|
||||||
dba_close($resource);
|
dba_close($resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function blockbot_log_activitypub(string $url, string $agent)
|
||||||
|
{
|
||||||
|
if (!DI::config()->get('blockbot', 'logging')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$bot = ['/.well-known/nodeinfo', '/nodeinfo/2.0', '/nodeinfo/1.0'];
|
||||||
|
if (in_array($url, $bot)) {
|
||||||
|
blockbot_save('activitypub-stats', $agent);
|
||||||
|
}
|
||||||
|
|
||||||
|
$bot = ['/api/v1/instance', '/api/v2/instance', '/api/v1/instance/extended_description',
|
||||||
|
'/api/v1/instance/peers'];
|
||||||
|
if (in_array($url, $bot)) {
|
||||||
|
blockbot_save('activitypub-api-stats', $agent);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (substr($url, 0, 6) == '/api/v') {
|
||||||
|
blockbot_save('activitypub-api', $agent);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (($_SERVER['REQUEST_METHOD'] == 'POST') && in_array('inbox', explode('/', parse_url($url, PHP_URL_PATH)))) {
|
||||||
|
blockbot_save('activitypub-inbox-agents', $agent);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($_SERVER['HTTP_SIGNATURE']) && !empty(HTTPSignature::getSigner('', $_SERVER))) {
|
||||||
|
blockbot_save('activitypub-signature-agents', $agent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function blockbot_check_login_attempt(string $url, array $logdata)
|
function blockbot_check_login_attempt(string $url, array $logdata)
|
||||||
{
|
{
|
||||||
if (in_array(trim(parse_url($url, PHP_URL_PATH), '/'), ['login', 'lostpass', 'register'])) {
|
if (in_array(trim(parse_url($url, PHP_URL_PATH), '/'), ['login', 'lostpass', 'register'])) {
|
||||||
|
@ -428,7 +461,7 @@ function blockbot_is_social_media(array $parts): bool
|
||||||
|
|
||||||
$agents = [
|
$agents = [
|
||||||
'facebookexternalhit', 'twitterbot', 'mastodon', 'facebookexternalua',
|
'facebookexternalhit', 'twitterbot', 'mastodon', 'facebookexternalua',
|
||||||
'friendica', 'diasporafederation', 'buzzrelay', 'activityrelay',
|
'friendica', 'diasporafederation', 'buzzrelay', 'activityrelay', 'drupal',
|
||||||
'aoderelay', 'ap-relay', 'peertube', 'misskey', 'pleroma', 'foundkey', 'akkoma',
|
'aoderelay', 'ap-relay', 'peertube', 'misskey', 'pleroma', 'foundkey', 'akkoma',
|
||||||
'lemmy', 'calckey', 'mobilizon', 'zot', 'camo-rs', 'gotosocial', 'pixelfed',
|
'lemmy', 'calckey', 'mobilizon', 'zot', 'camo-rs', 'gotosocial', 'pixelfed',
|
||||||
'pixelfedbot', 'app.wafrn.net', 'go-camo', 'http://a.gup.pe', 'iceshrimp',
|
'pixelfedbot', 'app.wafrn.net', 'go-camo', 'http://a.gup.pe', 'iceshrimp',
|
||||||
|
@ -466,6 +499,7 @@ function blockbot_is_fediverse_client(array $parts): bool
|
||||||
'megalodonandroid', 'fedilab', 'mastodonapp', 'toot!', 'intravnews',
|
'megalodonandroid', 'fedilab', 'mastodonapp', 'toot!', 'intravnews',
|
||||||
'pixeldroid', 'greatnews', 'protopage', 'newsfox', 'vienna', 'wp-urldetails', 'husky',
|
'pixeldroid', 'greatnews', 'protopage', 'newsfox', 'vienna', 'wp-urldetails', 'husky',
|
||||||
'activitypub-go-http-client', 'mobilesafari', 'mastodon-ios', 'mastodonpy', 'techniverse',
|
'activitypub-go-http-client', 'mobilesafari', 'mastodon-ios', 'mastodonpy', 'techniverse',
|
||||||
|
'relatica',
|
||||||
];
|
];
|
||||||
|
|
||||||
foreach ($parts as $part) {
|
foreach ($parts as $part) {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Name: Bluesky Connector
|
* Name: Bluesky Connector
|
||||||
* Description: Post to Bluesky
|
* Description: Post to Bluesky, import timelines and feeds
|
||||||
* Version: 1.1
|
* Version: 1.1
|
||||||
* Author: Michael Vogel <https://pirati.ca/profile/heluecht>
|
* Author: Michael Vogel <https://pirati.ca/profile/heluecht>
|
||||||
*
|
*
|
||||||
|
@ -10,6 +10,8 @@
|
||||||
* - Outgoing mentions
|
* - Outgoing mentions
|
||||||
*
|
*
|
||||||
* At some point in time:
|
* At some point in time:
|
||||||
|
* - post videos
|
||||||
|
* - direct messages
|
||||||
* - Sending Quote shares https://atproto.com/lexicons/app-bsky-embed#appbskyembedrecord and https://atproto.com/lexicons/app-bsky-embed#appbskyembedrecordwithmedia
|
* - Sending Quote shares https://atproto.com/lexicons/app-bsky-embed#appbskyembedrecord and https://atproto.com/lexicons/app-bsky-embed#appbskyembedrecordwithmedia
|
||||||
*
|
*
|
||||||
* Possibly not possible:
|
* Possibly not possible:
|
||||||
|
@ -36,6 +38,7 @@ use Friendica\Core\Worker;
|
||||||
use Friendica\Database\DBA;
|
use Friendica\Database\DBA;
|
||||||
use Friendica\DI;
|
use Friendica\DI;
|
||||||
use Friendica\Model\Contact;
|
use Friendica\Model\Contact;
|
||||||
|
use Friendica\Model\Conversation;
|
||||||
use Friendica\Model\GServer;
|
use Friendica\Model\GServer;
|
||||||
use Friendica\Model\Item;
|
use Friendica\Model\Item;
|
||||||
use Friendica\Model\ItemURI;
|
use Friendica\Model\ItemURI;
|
||||||
|
@ -45,10 +48,12 @@ use Friendica\Model\Tag;
|
||||||
use Friendica\Model\User;
|
use Friendica\Model\User;
|
||||||
use Friendica\Network\HTTPClient\Client\HttpClientAccept;
|
use Friendica\Network\HTTPClient\Client\HttpClientAccept;
|
||||||
use Friendica\Network\HTTPClient\Client\HttpClientOptions;
|
use Friendica\Network\HTTPClient\Client\HttpClientOptions;
|
||||||
|
use Friendica\Network\HTTPClient\Client\HttpClientRequest;
|
||||||
use Friendica\Object\Image;
|
use Friendica\Object\Image;
|
||||||
use Friendica\Protocol\Activity;
|
use Friendica\Protocol\Activity;
|
||||||
use Friendica\Protocol\Relay;
|
use Friendica\Protocol\Relay;
|
||||||
use Friendica\Util\DateTimeFormat;
|
use Friendica\Util\DateTimeFormat;
|
||||||
|
use Friendica\Util\Network;
|
||||||
use Friendica\Util\Strings;
|
use Friendica\Util\Strings;
|
||||||
|
|
||||||
const BLUESKY_DEFAULT_POLL_INTERVAL = 10; // given in minutes
|
const BLUESKY_DEFAULT_POLL_INTERVAL = 10; // given in minutes
|
||||||
|
@ -68,6 +73,7 @@ const BLUEKSY_STATUS_TOKEN_FAIL = 13;
|
||||||
const BLUESKY_DIRECTORY = 'https://plc.directory'; // Path to the directory server service to fetch the PDS of a given DID
|
const BLUESKY_DIRECTORY = 'https://plc.directory'; // Path to the directory server service to fetch the PDS of a given DID
|
||||||
const BLUESKY_PDS = 'https://bsky.social'; // Path to the personal data server service (PDS) to fetch the DID for a given handle
|
const BLUESKY_PDS = 'https://bsky.social'; // Path to the personal data server service (PDS) to fetch the DID for a given handle
|
||||||
const BLUESKY_WEB = 'https://bsky.app'; // Path to the web interface with the user profile and posts
|
const BLUESKY_WEB = 'https://bsky.app'; // Path to the web interface with the user profile and posts
|
||||||
|
const BLUESKY_HOSTNAME = 'bsky.social'; // Host name to be added to the handle if incomplete
|
||||||
|
|
||||||
function bluesky_install()
|
function bluesky_install()
|
||||||
{
|
{
|
||||||
|
@ -128,8 +134,13 @@ function bluesky_probe_detect(array &$hookData)
|
||||||
|
|
||||||
if (parse_url($hookData['uri'], PHP_URL_SCHEME) == 'did') {
|
if (parse_url($hookData['uri'], PHP_URL_SCHEME) == 'did') {
|
||||||
$did = $hookData['uri'];
|
$did = $hookData['uri'];
|
||||||
} elseif (preg_match('#^' . BLUESKY_WEB . '/profile/(.+)#', $hookData['uri'], $matches)) {
|
} elseif (parse_url($hookData['uri'], PHP_URL_PATH) == $hookData['uri'] && strpos($hookData['uri'], '@') === false) {
|
||||||
$did = bluesky_get_did($matches[1]);
|
$did = bluesky_get_did($hookData['uri'], $pconfig['uid']);
|
||||||
|
if (empty($did)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} elseif (Network::isValidHttpUrl($hookData['uri'])) {
|
||||||
|
$did = bluesky_get_did_by_profile($hookData['uri'], $pconfig['uid']);
|
||||||
if (empty($did)) {
|
if (empty($did)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -143,23 +154,18 @@ function bluesky_probe_detect(array &$hookData)
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = bluesky_xrpc_get($pconfig['uid'], 'app.bsky.actor.getProfile', ['actor' => $did]);
|
$data = bluesky_xrpc_get($pconfig['uid'], 'app.bsky.actor.getProfile', ['actor' => $did]);
|
||||||
if (empty($data)) {
|
if (empty($data) || empty($data->did)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$hookData['result'] = bluesky_get_contact_fields($data, 0, $pconfig['uid'], false);
|
$hookData['result'] = bluesky_get_contact_fields($data, 0, $pconfig['uid'], true);
|
||||||
|
|
||||||
$hookData['result']['baseurl'] = bluesky_get_pds($did);
|
|
||||||
|
|
||||||
// Preparing probe data. This differs slightly from the contact array
|
// Preparing probe data. This differs slightly from the contact array
|
||||||
$hookData['result']['about'] = HTML::toBBCode($data->description ?? '');
|
|
||||||
$hookData['result']['photo'] = $data->avatar ?? '';
|
$hookData['result']['photo'] = $data->avatar ?? '';
|
||||||
$hookData['result']['header'] = $data->banner ?? '';
|
|
||||||
$hookData['result']['batch'] = '';
|
$hookData['result']['batch'] = '';
|
||||||
$hookData['result']['notify'] = '';
|
$hookData['result']['notify'] = '';
|
||||||
$hookData['result']['poll'] = '';
|
$hookData['result']['poll'] = '';
|
||||||
$hookData['result']['poco'] = '';
|
$hookData['result']['poco'] = '';
|
||||||
$hookData['result']['pubkey'] = '';
|
|
||||||
$hookData['result']['priority'] = 0;
|
$hookData['result']['priority'] = 0;
|
||||||
$hookData['result']['guid'] = '';
|
$hookData['result']['guid'] = '';
|
||||||
}
|
}
|
||||||
|
@ -180,17 +186,17 @@ function bluesky_item_by_link(array &$hookData)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$did = bluesky_get_did($matches[1]);
|
$did = bluesky_get_did($matches[1], $hookData['uid']);
|
||||||
if (empty($did)) {
|
if (empty($did)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger::debug('Found bluesky post', ['url' => $hookData['uri'], 'handle' => $matches[1], 'did' => $did, 'cid' => $matches[2]]);
|
Logger::debug('Found bluesky post', ['url' => $hookData['uri'], 'did' => $did, 'cid' => $matches[2]]);
|
||||||
|
|
||||||
$uri = 'at://' . $did . '/app.bsky.feed.post/' . $matches[2];
|
$uri = 'at://' . $did . '/app.bsky.feed.post/' . $matches[2];
|
||||||
|
|
||||||
$uri = bluesky_fetch_missing_post($uri, $hookData['uid'], $hookData['uid'], Item::PR_FETCHED, 0, 0, 0);
|
$uri = bluesky_fetch_missing_post($uri, $hookData['uid'], $hookData['uid'], Item::PR_FETCHED, 0, 0, 0);
|
||||||
Logger::debug('Got post', ['profile' => $matches[1], 'cid' => $matches[2], 'result' => $uri]);
|
Logger::debug('Got post', ['did' => $did, 'cid' => $matches[2], 'result' => $uri]);
|
||||||
if (!empty($uri)) {
|
if (!empty($uri)) {
|
||||||
$item = Post::selectFirst(['id'], ['uri' => $uri, 'uid' => $hookData['uid']]);
|
$item = Post::selectFirst(['id'], ['uri' => $uri, 'uid' => $hookData['uid']]);
|
||||||
if (!empty($item['id'])) {
|
if (!empty($item['id'])) {
|
||||||
|
@ -273,14 +279,12 @@ function bluesky_block(array &$hook_data)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger::debug('Check if contact is bluesky', ['data' => $hook_data]);
|
if ($hook_data['contact']['network'] != Protocol::BLUESKY) {
|
||||||
$contact = DBA::selectFirst('contact', [], ['network' => Protocol::BLUESKY, 'url' => $hook_data['url'], 'uid' => [0, $hook_data['uid']]]);
|
|
||||||
if (empty($contact)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$record = [
|
$record = [
|
||||||
'subject' => $contact['url'],
|
'subject' => $hook_data['contact']['url'],
|
||||||
'createdAt' => DateTimeFormat::utcNow(DateTimeFormat::ATOM),
|
'createdAt' => DateTimeFormat::utcNow(DateTimeFormat::ATOM),
|
||||||
'$type' => 'app.bsky.graph.block'
|
'$type' => 'app.bsky.graph.block'
|
||||||
];
|
];
|
||||||
|
@ -293,9 +297,9 @@ function bluesky_block(array &$hook_data)
|
||||||
|
|
||||||
$activity = bluesky_xrpc_post($hook_data['uid'], 'com.atproto.repo.createRecord', $post);
|
$activity = bluesky_xrpc_post($hook_data['uid'], 'com.atproto.repo.createRecord', $post);
|
||||||
if (!empty($activity->uri)) {
|
if (!empty($activity->uri)) {
|
||||||
$cdata = Contact::getPublicAndUserContactID($hook_data['contact']['id'], $hook_data['uid']);
|
$ucid = Contact::getUserContactId($hook_data['contact']['id'], $hook_data['uid']);
|
||||||
if (!empty($cdata['user'])) {
|
if ($ucid) {
|
||||||
Contact::remove($cdata['user']);
|
Contact::remove($ucid);
|
||||||
}
|
}
|
||||||
Logger::debug('Successfully blocked contact', ['url' => $hook_data['contact']['url'], 'uri' => $activity->uri]);
|
Logger::debug('Successfully blocked contact', ['url' => $hook_data['contact']['url'], 'uri' => $activity->uri]);
|
||||||
}
|
}
|
||||||
|
@ -343,36 +347,41 @@ function bluesky_settings(array &$data)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$enabled = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'post') ?? false;
|
$enabled = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'post') ?? false;
|
||||||
$def_enabled = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'post_by_default') ?? false;
|
$def_enabled = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'post_by_default') ?? false;
|
||||||
$pds = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'pds');
|
$pds = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'pds');
|
||||||
$handle = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'handle');
|
$handle = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'handle');
|
||||||
$did = bluesky_get_user_did(DI::userSession()->getLocalUserId());
|
$did = bluesky_get_user_did(DI::userSession()->getLocalUserId());
|
||||||
$token = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'access_token');
|
$token = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'access_token');
|
||||||
$import = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'import') ?? false;
|
$import = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'import') ?? false;
|
||||||
$import_feeds = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'import_feeds') ?? false;
|
$import_feeds = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'import_feeds') ?? false;
|
||||||
$custom_handle = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'friendica_handle') ?? false;
|
$complete_threads = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'complete_threads') ?? false;
|
||||||
|
$custom_handle = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'friendica_handle') ?? false;
|
||||||
|
|
||||||
if (DI::config()->get('bluesky', 'friendica_handles')) {
|
if (DI::config()->get('bluesky', 'friendica_handles')) {
|
||||||
$self = User::getById(DI::userSession()->getLocalUserId(), ['nickname']);
|
$self = User::getById(DI::userSession()->getLocalUserId(), ['nickname']);
|
||||||
$handle = $self['nickname'] . '.' . DI::baseUrl()->getHost();
|
$host_handle = $self['nickname'] . '.' . DI::baseUrl()->getHost();
|
||||||
$friendica_handle = ['bluesky_friendica_handle', DI::l10n()->t('Allow to use %s as your Bluesky handle.', $handle), $custom_handle, DI::l10n()->t('When enabled, you can use %s as your Bluesky handle. After you enabled this option, please go to https://bsky.app/settings and select to change your handle. Select that you have got your own domain. Then enter %s and select "No DNS Panel". Then select "Verify Text File".', $handle, $handle)];
|
$friendica_handle = ['bluesky_friendica_handle', DI::l10n()->t('Allow to use %s as your Bluesky handle.', $host_handle), $custom_handle, DI::l10n()->t('When enabled, you can use %s as your Bluesky handle. After you enabled this option, please go to https://bsky.app/settings and select to change your handle. Select that you have got your own domain. Then enter %s and select "No DNS Panel". Then select "Verify Text File".', $host_handle, $host_handle)];
|
||||||
|
if ($custom_handle) {
|
||||||
|
$handle = $host_handle;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$friendica_handle = [];
|
$friendica_handle = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
$t = Renderer::getMarkupTemplate('connector_settings.tpl', 'addon/bluesky/');
|
$t = Renderer::getMarkupTemplate('connector_settings.tpl', 'addon/bluesky/');
|
||||||
$html = Renderer::replaceMacros($t, [
|
$html = Renderer::replaceMacros($t, [
|
||||||
'$enable' => ['bluesky', DI::l10n()->t('Enable Bluesky Post Addon'), $enabled],
|
'$enable' => ['bluesky', DI::l10n()->t('Enable Bluesky Post Addon'), $enabled],
|
||||||
'$bydefault' => ['bluesky_bydefault', DI::l10n()->t('Post to Bluesky by default'), $def_enabled],
|
'$bydefault' => ['bluesky_bydefault', DI::l10n()->t('Post to Bluesky by default'), $def_enabled],
|
||||||
'$import' => ['bluesky_import', DI::l10n()->t('Import the remote timeline'), $import],
|
'$import' => ['bluesky_import', DI::l10n()->t('Import the remote timeline'), $import],
|
||||||
'$import_feeds' => ['bluesky_import_feeds', DI::l10n()->t('Import the pinned feeds'), $import_feeds, DI::l10n()->t('When activated, Posts will be imported from all the feeds that you pinned in Bluesky.')],
|
'$import_feeds' => ['bluesky_import_feeds', DI::l10n()->t('Import the pinned feeds'), $import_feeds, DI::l10n()->t('When activated, Posts will be imported from all the feeds that you pinned in Bluesky.')],
|
||||||
'$custom_handle' => $friendica_handle,
|
'$complete_threads' => ['bluesky_complete_threads', DI::l10n()->t('Complete the threads'), $complete_threads, DI::l10n()->t('When activated, the system fetches additional replies for the posts in the timeline. This leads to more complete threads.')],
|
||||||
'$pds' => ['bluesky_pds', DI::l10n()->t('Personal Data Server'), $pds, DI::l10n()->t('The personal data server (PDS) is the system that hosts your profile.'), '', 'readonly'],
|
'$custom_handle' => $friendica_handle,
|
||||||
'$handle' => ['bluesky_handle', DI::l10n()->t('Bluesky handle'), $handle],
|
'$pds' => ['bluesky_pds', DI::l10n()->t('Personal Data Server'), $pds, DI::l10n()->t('The personal data server (PDS) is the system that hosts your profile.'), '', 'readonly'],
|
||||||
'$did' => ['bluesky_did', DI::l10n()->t('Bluesky DID'), $did, DI::l10n()->t('This is the unique identifier. It will be fetched automatically, when the handle is entered.'), '', 'readonly'],
|
'$handle' => ['bluesky_handle', DI::l10n()->t('Bluesky handle'), $handle, '', '', $custom_handle ? 'readonly' : ''],
|
||||||
'$password' => ['bluesky_password', DI::l10n()->t('Bluesky app password'), '', DI::l10n()->t("Please don't add your real password here, but instead create a specific app password in the Bluesky settings.")],
|
'$did' => ['bluesky_did', DI::l10n()->t('Bluesky DID'), $did, DI::l10n()->t('This is the unique identifier. It will be fetched automatically, when the handle is entered.'), '', 'readonly'],
|
||||||
'$status' => bluesky_get_status($handle, $did, $pds, $token),
|
'$password' => ['bluesky_password', DI::l10n()->t('Bluesky app password'), '', DI::l10n()->t("Please don't add your real password here, but instead create a specific app password in the Bluesky settings.")],
|
||||||
|
'$status' => bluesky_get_status($handle, $did, $pds, $token),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
|
@ -440,7 +449,8 @@ function bluesky_settings_post(array &$b)
|
||||||
DI::pConfig()->set(DI::userSession()->getLocalUserId(), 'bluesky', 'handle', $handle);
|
DI::pConfig()->set(DI::userSession()->getLocalUserId(), 'bluesky', 'handle', $handle);
|
||||||
DI::pConfig()->set(DI::userSession()->getLocalUserId(), 'bluesky', 'import', intval($_POST['bluesky_import']));
|
DI::pConfig()->set(DI::userSession()->getLocalUserId(), 'bluesky', 'import', intval($_POST['bluesky_import']));
|
||||||
DI::pConfig()->set(DI::userSession()->getLocalUserId(), 'bluesky', 'import_feeds', intval($_POST['bluesky_import_feeds']));
|
DI::pConfig()->set(DI::userSession()->getLocalUserId(), 'bluesky', 'import_feeds', intval($_POST['bluesky_import_feeds']));
|
||||||
DI::pConfig()->set(DI::userSession()->getLocalUserId(), 'bluesky', 'friendica_handle', intval($_POST['bluesky_friendica_handle']));
|
DI::pConfig()->set(DI::userSession()->getLocalUserId(), 'bluesky', 'complete_threads', intval($_POST['bluesky_complete_threads']));
|
||||||
|
DI::pConfig()->set(DI::userSession()->getLocalUserId(), 'bluesky', 'friendica_handle', intval($_POST['bluesky_friendica_handle'] ?? false));
|
||||||
|
|
||||||
if (!empty($handle)) {
|
if (!empty($handle)) {
|
||||||
$did = bluesky_get_user_did(DI::userSession()->getLocalUserId(), empty($old_did) || $old_handle != $handle);
|
$did = bluesky_get_user_did(DI::userSession()->getLocalUserId(), empty($old_did) || $old_handle != $handle);
|
||||||
|
@ -510,9 +520,10 @@ function bluesky_cron()
|
||||||
|
|
||||||
$abandon_limit = date(DateTimeFormat::MYSQL, time() - $abandon_days * 86400);
|
$abandon_limit = date(DateTimeFormat::MYSQL, time() - $abandon_days * 86400);
|
||||||
|
|
||||||
$pconfigs = DBA::selectToArray('pconfig', [], ['cat' => 'bluesky', 'k' => 'import', 'v' => true]);
|
$pconfigs = DBA::selectToArray('pconfig', [], ["`cat` = ? AND `k` IN (?, ?) AND `v`", 'bluesky', 'import', 'import_feeds']);
|
||||||
foreach ($pconfigs as $pconfig) {
|
foreach ($pconfigs as $pconfig) {
|
||||||
if (empty(bluesky_get_user_did($pconfig['uid']))) {
|
if (empty(bluesky_get_user_did($pconfig['uid']))) {
|
||||||
|
Logger::debug('User has got no valid DID', ['uid' => $pconfig['uid']]);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -524,19 +535,27 @@ function bluesky_cron()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Refresh the token now, so that it doesn't need to be refreshed in parallel by the following workers
|
// Refresh the token now, so that it doesn't need to be refreshed in parallel by the following workers
|
||||||
|
Logger::debug('Refresh the token', ['uid' => $pconfig['uid']]);
|
||||||
bluesky_get_token($pconfig['uid']);
|
bluesky_get_token($pconfig['uid']);
|
||||||
|
|
||||||
Worker::add(['priority' => Worker::PRIORITY_MEDIUM, 'force_priority' => true], 'addon/bluesky/bluesky_notifications.php', $pconfig['uid'], $last);
|
Worker::add(['priority' => Worker::PRIORITY_MEDIUM, 'force_priority' => true], 'addon/bluesky/bluesky_notifications.php', $pconfig['uid']);
|
||||||
Worker::add(['priority' => Worker::PRIORITY_MEDIUM, 'force_priority' => true], 'addon/bluesky/bluesky_timeline.php', $pconfig['uid'], $last);
|
if (DI::pConfig()->get($pconfig['uid'], 'bluesky', 'import')) {
|
||||||
|
Worker::add(['priority' => Worker::PRIORITY_MEDIUM, 'force_priority' => true], 'addon/bluesky/bluesky_timeline.php', $pconfig['uid']);
|
||||||
|
}
|
||||||
if (DI::pConfig()->get($pconfig['uid'], 'bluesky', 'import_feeds')) {
|
if (DI::pConfig()->get($pconfig['uid'], 'bluesky', 'import_feeds')) {
|
||||||
|
Logger::debug('Fetch feeds for user', ['uid' => $pconfig['uid']]);
|
||||||
$feeds = bluesky_get_feeds($pconfig['uid']);
|
$feeds = bluesky_get_feeds($pconfig['uid']);
|
||||||
foreach ($feeds as $feed) {
|
foreach ($feeds as $feed) {
|
||||||
Worker::add(['priority' => Worker::PRIORITY_MEDIUM, 'force_priority' => true], 'addon/bluesky/bluesky_feed.php', $pconfig['uid'], $feed, $last);
|
Worker::add(['priority' => Worker::PRIORITY_MEDIUM, 'force_priority' => true], 'addon/bluesky/bluesky_feed.php', $pconfig['uid'], $feed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Logger::debug('Polling done for user', ['uid' => $pconfig['uid']]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Logger::notice('Polling done for all users');
|
||||||
|
|
||||||
|
DI::keyValue()->set('bluesky_last_poll', time());
|
||||||
|
|
||||||
$last_clean = DI::keyValue()->get('bluesky_last_clean');
|
$last_clean = DI::keyValue()->get('bluesky_last_clean');
|
||||||
if (empty($last_clean) || ($last_clean + 86400 < time())) {
|
if (empty($last_clean) || ($last_clean + 86400 < time())) {
|
||||||
Logger::notice('Start contact cleanup');
|
Logger::notice('Start contact cleanup');
|
||||||
|
@ -550,8 +569,6 @@ function bluesky_cron()
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger::notice('cron_end');
|
Logger::notice('cron_end');
|
||||||
|
|
||||||
DI::keyValue()->set('bluesky_last_poll', time());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function bluesky_hook_fork(array &$b)
|
function bluesky_hook_fork(array &$b)
|
||||||
|
@ -570,13 +587,13 @@ function bluesky_hook_fork(array &$b)
|
||||||
|
|
||||||
if (DI::pConfig()->get($post['uid'], 'bluesky', 'import')) {
|
if (DI::pConfig()->get($post['uid'], 'bluesky', 'import')) {
|
||||||
// Don't post if it isn't a reply to a bluesky post
|
// Don't post if it isn't a reply to a bluesky post
|
||||||
if (($post['parent'] != $post['id']) && !Post::exists(['id' => $post['parent'], 'network' => Protocol::BLUESKY])) {
|
if (($post['gravity'] != Item::GRAVITY_PARENT) && !Post::exists(['id' => $post['parent'], 'network' => Protocol::BLUESKY])) {
|
||||||
Logger::notice('No bluesky parent found', ['item' => $post['id']]);
|
Logger::notice('No bluesky parent found', ['item' => $post['id']]);
|
||||||
$b['execute'] = false;
|
$b['execute'] = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} elseif (!strstr($post['postopts'] ?? '', 'bluesky') || ($post['parent'] != $post['id']) || $post['private']) {
|
} elseif (!strstr($post['postopts'] ?? '', 'bluesky') || ($post['gravity'] != Item::GRAVITY_PARENT) || ($post['private'] == Item::PRIVATE)) {
|
||||||
DI::logger()->info('Activities are never exported when we don\'t import the bluesky timeline', ['uid' => $post['uid']]);
|
DI::logger()->info('Post will not be exported', ['uid' => $post['uid'], 'postopts' => $post['postopts'], 'gravity' => $post['gravity'], 'private' => $post['private']]);
|
||||||
$b['execute'] = false;
|
$b['execute'] = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -584,15 +601,11 @@ function bluesky_hook_fork(array &$b)
|
||||||
|
|
||||||
function bluesky_post_local(array &$b)
|
function bluesky_post_local(array &$b)
|
||||||
{
|
{
|
||||||
if ($b['edit']) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!DI::userSession()->getLocalUserId() || (DI::userSession()->getLocalUserId() != $b['uid'])) {
|
if (!DI::userSession()->getLocalUserId() || (DI::userSession()->getLocalUserId() != $b['uid'])) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($b['private'] || $b['parent']) {
|
if ($b['edit'] || ($b['private'] == Item::PRIVATE) || ($b['gravity'] != Item::GRAVITY_PARENT)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -650,7 +663,7 @@ function bluesky_send(array &$b)
|
||||||
bluesky_create_activity($b, $parent);
|
bluesky_create_activity($b, $parent);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
} elseif ($b['private'] || !strstr($b['postopts'], 'bluesky')) {
|
} elseif (($b['private'] == Item::PRIVATE) || !strstr($b['postopts'], 'bluesky')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -697,7 +710,7 @@ function bluesky_create_activity(array $item, stdClass $parent = null)
|
||||||
}
|
}
|
||||||
|
|
||||||
$activity = bluesky_xrpc_post($uid, 'com.atproto.repo.createRecord', $post);
|
$activity = bluesky_xrpc_post($uid, 'com.atproto.repo.createRecord', $post);
|
||||||
if (empty($activity)) {
|
if (empty($activity->uri)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Logger::debug('Activity done', ['return' => $activity]);
|
Logger::debug('Activity done', ['return' => $activity]);
|
||||||
|
@ -781,7 +794,7 @@ function bluesky_create_post(array $item, stdClass $root = null, stdClass $paren
|
||||||
];
|
];
|
||||||
|
|
||||||
$parent = bluesky_xrpc_post($uid, 'com.atproto.repo.createRecord', $post);
|
$parent = bluesky_xrpc_post($uid, 'com.atproto.repo.createRecord', $post);
|
||||||
if (empty($parent)) {
|
if (empty($parent->uri)) {
|
||||||
if ($part == 0) {
|
if ($part == 0) {
|
||||||
Worker::defer();
|
Worker::defer();
|
||||||
}
|
}
|
||||||
|
@ -959,11 +972,12 @@ function bluesky_upload_blob(int $uid, array $photo): ?stdClass
|
||||||
Logger::info('Uploading', ['uid' => $uid, 'retrial' => $retrial, 'height' => $new_height, 'width' => $new_width, 'size' => $new_size, 'orig-height' => $height, 'orig-width' => $width, 'orig-size' => $size]);
|
Logger::info('Uploading', ['uid' => $uid, 'retrial' => $retrial, 'height' => $new_height, 'width' => $new_width, 'size' => $new_size, 'orig-height' => $height, 'orig-width' => $width, 'orig-size' => $size]);
|
||||||
|
|
||||||
$data = bluesky_post($uid, '/xrpc/com.atproto.repo.uploadBlob', $content, ['Content-type' => $photo['type'], 'Authorization' => ['Bearer ' . bluesky_get_token($uid)]]);
|
$data = bluesky_post($uid, '/xrpc/com.atproto.repo.uploadBlob', $content, ['Content-type' => $photo['type'], 'Authorization' => ['Bearer ' . bluesky_get_token($uid)]]);
|
||||||
if (empty($data)) {
|
if (empty($data) || empty($data->blob)) {
|
||||||
Logger::info('Uploading failed', ['uid' => $uid, 'retrial' => $retrial, 'height' => $new_height, 'width' => $new_width, 'size' => $new_size, 'orig-height' => $height, 'orig-width' => $width, 'orig-size' => $size]);
|
Logger::info('Uploading failed', ['uid' => $uid, 'retrial' => $retrial, 'height' => $new_height, 'width' => $new_width, 'size' => $new_size, 'orig-height' => $height, 'orig-width' => $width, 'orig-size' => $size]);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Item::incrementOutbound(Protocol::BLUESKY);
|
||||||
Logger::debug('Uploaded blob', ['return' => $data, 'uid' => $uid, 'retrial' => $retrial, 'height' => $new_height, 'width' => $new_width, 'size' => $new_size, 'orig-height' => $height, 'orig-width' => $width, 'orig-size' => $size]);
|
Logger::debug('Uploaded blob', ['return' => $data, 'uid' => $uid, 'retrial' => $retrial, 'height' => $new_height, 'width' => $new_width, 'size' => $new_size, 'orig-height' => $height, 'orig-width' => $width, 'orig-size' => $size]);
|
||||||
return $data->blob;
|
return $data->blob;
|
||||||
}
|
}
|
||||||
|
@ -979,7 +993,7 @@ function bluesky_delete_post(string $uri, int $uid)
|
||||||
Logger::debug('Deleted', ['parts' => $parts]);
|
Logger::debug('Deleted', ['parts' => $parts]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function bluesky_fetch_timeline(int $uid, int $last_poll)
|
function bluesky_fetch_timeline(int $uid)
|
||||||
{
|
{
|
||||||
$data = bluesky_xrpc_get($uid, 'app.bsky.feed.getTimeline');
|
$data = bluesky_xrpc_get($uid, 'app.bsky.feed.getTimeline');
|
||||||
if (empty($data)) {
|
if (empty($data)) {
|
||||||
|
@ -990,15 +1004,44 @@ function bluesky_fetch_timeline(int $uid, int $last_poll)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$last_post = DBA::selectFirst('post-thread-user', ['received'], ['network' => Protocol::BLUESKY, 'uid' => $uid], ['order' => ['received' => true]]);
|
||||||
|
$last_poll = !empty($last_post['received']) ? strtotime($last_post['received']) : 0;
|
||||||
|
|
||||||
foreach (array_reverse($data->feed) as $entry) {
|
foreach (array_reverse($data->feed) as $entry) {
|
||||||
|
$causer = bluesky_get_contact($entry->post->author, 0, $uid);
|
||||||
|
if (!empty($entry->reply)) {
|
||||||
|
if (!empty($entry->reply->root)) {
|
||||||
|
bluesky_complete_post($entry->reply->root, $uid, Item::PR_COMMENT, $causer['id'], $last_poll);
|
||||||
|
}
|
||||||
|
if (!empty($entry->reply->parent)) {
|
||||||
|
bluesky_complete_post($entry->reply->parent, $uid, Item::PR_COMMENT, $causer['id'], $last_poll);
|
||||||
|
}
|
||||||
|
}
|
||||||
bluesky_process_post($entry->post, $uid, $uid, Item::PR_NONE, 0, 0, $last_poll);
|
bluesky_process_post($entry->post, $uid, $uid, Item::PR_NONE, 0, 0, $last_poll);
|
||||||
if (!empty($entry->reason)) {
|
if (!empty($entry->reason)) {
|
||||||
bluesky_process_reason($entry->reason, bluesky_get_uri($entry->post), $uid);
|
bluesky_process_reason($entry->reason, bluesky_get_uri($entry->post), $uid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// @todo Support paging
|
function bluesky_complete_post(stdClass $post, int $uid, int $post_reason, int $causer, int $last_poll): int
|
||||||
// [cursor] => 1684670516000::bafyreidq3ilwslmlx72jf5vrk367xcc63s6lrhzlyup2bi3zwcvso6w2vi
|
{
|
||||||
|
$complete = DI::pConfig()->get($uid, 'bluesky', 'complete_threads');
|
||||||
|
$existing_uri = bluesky_fetch_post(bluesky_get_uri($post), $uid);
|
||||||
|
if (!empty($existing_uri)) {
|
||||||
|
$comments = Post::countPosts(['thr-parent' => $existing_uri, 'gravity' => Item::GRAVITY_COMMENT]);
|
||||||
|
if (($post->replyCount <= $comments) || !$complete) {
|
||||||
|
return bluesky_fetch_uri_id($existing_uri, $uid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($complete) {
|
||||||
|
$uri = bluesky_fetch_missing_post($post->uri, $uid, $uid, $post_reason, $causer, 0, $last_poll, '', true);
|
||||||
|
$uri_id = bluesky_fetch_uri_id($uri, $uid);
|
||||||
|
} else {
|
||||||
|
$uri_id = bluesky_process_post($post, $uid, $uid, $post_reason, $causer, 0, $last_poll);
|
||||||
|
}
|
||||||
|
return $uri_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
function bluesky_process_reason(stdClass $reason, string $uri, int $uid)
|
function bluesky_process_reason(stdClass $reason, string $uri, int $uid)
|
||||||
|
@ -1012,6 +1055,7 @@ function bluesky_process_reason(stdClass $reason, string $uri, int $uid)
|
||||||
|
|
||||||
$item = [
|
$item = [
|
||||||
'network' => Protocol::BLUESKY,
|
'network' => Protocol::BLUESKY,
|
||||||
|
'protocol' => Conversation::PARCEL_CONNECTOR,
|
||||||
'uid' => $uid,
|
'uid' => $uid,
|
||||||
'wall' => false,
|
'wall' => false,
|
||||||
'uri' => $reason->by->did . '/app.bsky.feed.repost/' . $reason->indexedAt,
|
'uri' => $reason->by->did . '/app.bsky.feed.repost/' . $reason->indexedAt,
|
||||||
|
@ -1037,17 +1081,21 @@ function bluesky_process_reason(stdClass $reason, string $uri, int $uid)
|
||||||
$item['owner-link'] = $item['author-link'];
|
$item['owner-link'] = $item['author-link'];
|
||||||
$item['owner-avatar'] = $item['author-avatar'];
|
$item['owner-avatar'] = $item['author-avatar'];
|
||||||
if (Item::insert($item)) {
|
if (Item::insert($item)) {
|
||||||
$cdata = Contact::getPublicAndUserContactID($contact['id'], $uid);
|
$pcid = Contact::getPublicContactId($contact['id'], $uid);
|
||||||
Item::update(['post-reason' => Item::PR_ANNOUNCEMENT, 'causer-id' => $cdata['public']], ['uri' => $uri, 'uid' => $uid]);
|
Item::update(['post-reason' => Item::PR_ANNOUNCEMENT, 'causer-id' => $pcid], ['uri' => $uri, 'uid' => $uid]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function bluesky_fetch_notifications(int $uid, int $last_poll)
|
function bluesky_fetch_notifications(int $uid)
|
||||||
{
|
{
|
||||||
$data = bluesky_xrpc_get($uid, 'app.bsky.notification.listNotifications');
|
$data = bluesky_xrpc_get($uid, 'app.bsky.notification.listNotifications');
|
||||||
if (empty($data->notifications)) {
|
if (empty($data->notifications)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$last_post = DBA::selectFirst('post-thread-user', ['received'], ['network' => Protocol::BLUESKY, 'uid' => $uid], ['order' => ['received' => true]]);
|
||||||
|
$last_poll = !empty($last_post['received']) ? strtotime($last_post['received']) : 0;
|
||||||
|
|
||||||
foreach ($data->notifications as $notification) {
|
foreach ($data->notifications as $notification) {
|
||||||
$uri = bluesky_get_uri($notification);
|
$uri = bluesky_get_uri($notification);
|
||||||
if (Post::exists(['uri' => $uri, 'uid' => $uid]) || Post::exists(['extid' => $uri, 'uid' => $uid])) {
|
if (Post::exists(['uri' => $uri, 'uid' => $uid]) || Post::exists(['extid' => $uri, 'uid' => $uid])) {
|
||||||
|
@ -1057,7 +1105,7 @@ function bluesky_fetch_notifications(int $uid, int $last_poll)
|
||||||
Logger::debug('Process notification', ['uid' => $uid, 'reason' => $notification->reason, 'uri' => $uri, 'indexedAt' => $notification->indexedAt]);
|
Logger::debug('Process notification', ['uid' => $uid, 'reason' => $notification->reason, 'uri' => $uri, 'indexedAt' => $notification->indexedAt]);
|
||||||
switch ($notification->reason) {
|
switch ($notification->reason) {
|
||||||
case 'like':
|
case 'like':
|
||||||
$item = bluesky_get_header($notification, $uri, $uid, $uid);
|
$item = bluesky_get_header($notification, $uri, $uid, $uid, $last_poll);
|
||||||
$item['gravity'] = Item::GRAVITY_ACTIVITY;
|
$item['gravity'] = Item::GRAVITY_ACTIVITY;
|
||||||
$item['body'] = $item['verb'] = Activity::LIKE;
|
$item['body'] = $item['verb'] = Activity::LIKE;
|
||||||
$item['thr-parent'] = bluesky_get_uri($notification->record->subject);
|
$item['thr-parent'] = bluesky_get_uri($notification->record->subject);
|
||||||
|
@ -1071,7 +1119,7 @@ function bluesky_fetch_notifications(int $uid, int $last_poll)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'repost':
|
case 'repost':
|
||||||
$item = bluesky_get_header($notification, $uri, $uid, $uid);
|
$item = bluesky_get_header($notification, $uri, $uid, $uid, $last_poll);
|
||||||
$item['gravity'] = Item::GRAVITY_ACTIVITY;
|
$item['gravity'] = Item::GRAVITY_ACTIVITY;
|
||||||
$item['body'] = $item['verb'] = Activity::ANNOUNCE;
|
$item['body'] = $item['verb'] = Activity::ANNOUNCE;
|
||||||
$item['thr-parent'] = bluesky_get_uri($notification->record->subject);
|
$item['thr-parent'] = bluesky_get_uri($notification->record->subject);
|
||||||
|
@ -1114,7 +1162,7 @@ function bluesky_fetch_notifications(int $uid, int $last_poll)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function bluesky_fetch_feed(int $uid, string $feed, int $last_poll)
|
function bluesky_fetch_feed(int $uid, string $feed)
|
||||||
{
|
{
|
||||||
$data = bluesky_xrpc_get($uid, 'app.bsky.feed.getFeed', ['feed' => $feed]);
|
$data = bluesky_xrpc_get($uid, 'app.bsky.feed.getFeed', ['feed' => $feed]);
|
||||||
if (empty($data)) {
|
if (empty($data)) {
|
||||||
|
@ -1125,8 +1173,11 @@ function bluesky_fetch_feed(int $uid, string $feed, int $last_poll)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$last_post = DBA::selectFirst('post-thread-user', ['received'], ['network' => Protocol::BLUESKY, 'uid' => $uid], ['order' => ['received' => true]]);
|
||||||
|
$last_poll = !empty($last_post['received']) ? strtotime($last_post['received']) : 0;
|
||||||
|
|
||||||
$feeddata = bluesky_xrpc_get($uid, 'app.bsky.feed.getFeedGenerator', ['feed' => $feed]);
|
$feeddata = bluesky_xrpc_get($uid, 'app.bsky.feed.getFeedGenerator', ['feed' => $feed]);
|
||||||
if (!empty($feeddata)) {
|
if (!empty($feeddata) && !empty($feeddata->view)) {
|
||||||
$feedurl = $feeddata->view->uri;
|
$feedurl = $feeddata->view->uri;
|
||||||
$feedname = $feeddata->view->displayName;
|
$feedname = $feeddata->view->displayName;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1139,10 +1190,11 @@ function bluesky_fetch_feed(int $uid, string $feed, int $last_poll)
|
||||||
$languages = $entry->post->record->langs ?? [];
|
$languages = $entry->post->record->langs ?? [];
|
||||||
|
|
||||||
if (!Relay::isWantedLanguage($entry->post->record->text, 0, $contact['id'] ?? 0, $languages)) {
|
if (!Relay::isWantedLanguage($entry->post->record->text, 0, $contact['id'] ?? 0, $languages)) {
|
||||||
Logger::debug('Unwanted language detected', ['text' => $entry->post->record->text]);
|
Logger::debug('Unwanted language detected', ['languages' => $languages, 'text' => $entry->post->record->text]);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$uri_id = bluesky_process_post($entry->post, $uid, $uid, Item::PR_TAG, 0, 0, $last_poll);
|
$causer = bluesky_get_contact($entry->post->author, 0, $uid);
|
||||||
|
$uri_id = bluesky_complete_post($entry->post, $uid, Item::PR_TAG, $causer['id'], $last_poll);
|
||||||
if (!empty($uri_id)) {
|
if (!empty($uri_id)) {
|
||||||
$stored = Post\Category::storeFileByURIId($uri_id, $uid, Post\Category::SUBCRIPTION, $feedname, $feedurl);
|
$stored = Post\Category::storeFileByURIId($uri_id, $uid, Post\Category::SUBCRIPTION, $feedname, $feedurl);
|
||||||
Logger::debug('Stored tag subscription for user', ['uri-id' => $uri_id, 'uid' => $uid, 'name' => $feedname, 'url' => $feedurl, 'stored' => $stored]);
|
Logger::debug('Stored tag subscription for user', ['uri-id' => $uri_id, 'uid' => $uid, 'name' => $feedname, 'url' => $feedurl, 'stored' => $stored]);
|
||||||
|
@ -1170,7 +1222,7 @@ function bluesky_process_post(stdClass $post, int $uid, int $fetch_uid, int $pos
|
||||||
|
|
||||||
Logger::debug('Importing post', ['uid' => $uid, 'indexedAt' => $post->indexedAt, 'uri' => $post->uri, 'cid' => $post->cid, 'root' => $post->record->reply->root ?? '']);
|
Logger::debug('Importing post', ['uid' => $uid, 'indexedAt' => $post->indexedAt, 'uri' => $post->uri, 'cid' => $post->cid, 'root' => $post->record->reply->root ?? '']);
|
||||||
|
|
||||||
$item = bluesky_get_header($post, $uri, $uid, $fetch_uid);
|
$item = bluesky_get_header($post, $uri, $uid, $fetch_uid, $last_poll);
|
||||||
$item = bluesky_get_content($item, $post->record, $uri, $uid, $fetch_uid, $level, $last_poll);
|
$item = bluesky_get_content($item, $post->record, $uri, $uid, $fetch_uid, $level, $last_poll);
|
||||||
if (empty($item)) {
|
if (empty($item)) {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1194,7 +1246,7 @@ function bluesky_process_post(stdClass $post, int $uid, int $fetch_uid, int $pos
|
||||||
return bluesky_fetch_uri_id($uri, $uid);
|
return bluesky_fetch_uri_id($uri, $uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
function bluesky_get_header(stdClass $post, string $uri, int $uid, int $fetch_uid): array
|
function bluesky_get_header(stdClass $post, string $uri, int $uid, int $fetch_uid, int $last_poll = 0): array
|
||||||
{
|
{
|
||||||
$parts = bluesky_get_uri_parts($uri);
|
$parts = bluesky_get_uri_parts($uri);
|
||||||
if (empty($post->author) || empty($post->cid) || empty($parts->rkey)) {
|
if (empty($post->author) || empty($post->cid) || empty($parts->rkey)) {
|
||||||
|
@ -1203,10 +1255,12 @@ function bluesky_get_header(stdClass $post, string $uri, int $uid, int $fetch_ui
|
||||||
$contact = bluesky_get_contact($post->author, $uid, $fetch_uid);
|
$contact = bluesky_get_contact($post->author, $uid, $fetch_uid);
|
||||||
$item = [
|
$item = [
|
||||||
'network' => Protocol::BLUESKY,
|
'network' => Protocol::BLUESKY,
|
||||||
|
'protocol' => Conversation::PARCEL_CONNECTOR,
|
||||||
'uid' => $uid,
|
'uid' => $uid,
|
||||||
'wall' => false,
|
'wall' => false,
|
||||||
'uri' => $uri,
|
'uri' => $uri,
|
||||||
'guid' => $post->cid,
|
'guid' => $post->cid,
|
||||||
|
'received' => DateTimeFormat::utc($post->indexedAt, DateTimeFormat::MYSQL),
|
||||||
'private' => Item::UNLISTED,
|
'private' => Item::UNLISTED,
|
||||||
'verb' => Activity::POST,
|
'verb' => Activity::POST,
|
||||||
'contact-id' => $contact['id'],
|
'contact-id' => $contact['id'],
|
||||||
|
@ -1217,7 +1271,15 @@ function bluesky_get_header(stdClass $post, string $uri, int $uid, int $fetch_ui
|
||||||
'source' => json_encode($post),
|
'source' => json_encode($post),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
if (($last_poll != 0) && strtotime($item['received']) < $last_poll) {
|
||||||
|
unset($item['received']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$account = Contact::selectFirstAccountUser(['pid'], ['id' => $contact['id']]);
|
||||||
|
|
||||||
|
$item['author-id'] = $account['pid'];
|
||||||
$item['uri-id'] = ItemURI::getIdByURI($uri);
|
$item['uri-id'] = ItemURI::getIdByURI($uri);
|
||||||
|
$item['owner-id'] = $item['author-id'];
|
||||||
$item['owner-name'] = $item['author-name'];
|
$item['owner-name'] = $item['author-name'];
|
||||||
$item['owner-link'] = $item['author-link'];
|
$item['owner-link'] = $item['author-link'];
|
||||||
$item['owner-avatar'] = $item['author-avatar'];
|
$item['owner-avatar'] = $item['author-avatar'];
|
||||||
|
@ -1232,6 +1294,7 @@ function bluesky_get_header(stdClass $post, string $uri, int $uid, int $fetch_ui
|
||||||
// When "ver" is set to "1" it was flagged by some automated process.
|
// When "ver" is set to "1" it was flagged by some automated process.
|
||||||
if (empty($label->ver)) {
|
if (empty($label->ver)) {
|
||||||
$item['sensitive'] = true;
|
$item['sensitive'] = true;
|
||||||
|
$item['content-warning'] = $label->val ?? '';
|
||||||
Logger::debug('Sensitive content', ['uri-id' => $item['uri-id'], 'label' => $label]);
|
Logger::debug('Sensitive content', ['uri-id' => $item['uri-id'], 'label' => $label]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1311,10 +1374,6 @@ function bluesky_get_content(array $item, stdClass $record, string $uri, int $ui
|
||||||
$item['created'] = DateTimeFormat::utc($record->createdAt, DateTimeFormat::MYSQL);
|
$item['created'] = DateTimeFormat::utc($record->createdAt, DateTimeFormat::MYSQL);
|
||||||
$item['transmitted-languages'] = $record->langs ?? [];
|
$item['transmitted-languages'] = $record->langs ?? [];
|
||||||
|
|
||||||
if (($last_poll != 0) && strtotime($item['created']) > $last_poll) {
|
|
||||||
$item['received'] = $item['created'];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $item;
|
return $item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1392,6 +1451,19 @@ function bluesky_add_media(stdClass $embed, array $item, int $fetch_uid, int $le
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'app.bsky.embed.video#view':
|
||||||
|
$media = [
|
||||||
|
'uri-id' => $item['uri-id'],
|
||||||
|
'type' => Post\Media::HLS,
|
||||||
|
'url' => $embed->playlist,
|
||||||
|
'preview' => $embed->thumbnail,
|
||||||
|
'description' => $embed->alt ?? '',
|
||||||
|
'height' => $embed->aspectRatio->height ?? null,
|
||||||
|
'width' => $embed->aspectRatio->width ?? null,
|
||||||
|
];
|
||||||
|
Post\Media::insert($media);
|
||||||
|
break;
|
||||||
|
|
||||||
case 'app.bsky.embed.external#view':
|
case 'app.bsky.embed.external#view':
|
||||||
$media = [
|
$media = [
|
||||||
'uri-id' => $item['uri-id'],
|
'uri-id' => $item['uri-id'],
|
||||||
|
@ -1405,6 +1477,14 @@ function bluesky_add_media(stdClass $embed, array $item, int $fetch_uid, int $le
|
||||||
|
|
||||||
case 'app.bsky.embed.record#view':
|
case 'app.bsky.embed.record#view':
|
||||||
$original_uri = $uri = bluesky_get_uri($embed->record);
|
$original_uri = $uri = bluesky_get_uri($embed->record);
|
||||||
|
$type = '$type';
|
||||||
|
if (!empty($embed->record->record->$type)) {
|
||||||
|
$embed_type = $embed->record->record->$type;
|
||||||
|
if ($embed_type == 'app.bsky.graph.starterpack') {
|
||||||
|
bluesky_add_starterpack($item, $embed->record);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
$uri = bluesky_fetch_missing_post($uri, $item['uid'], $fetch_uid, Item::PR_FETCHED, $item['contact-id'], $level, $last_poll);
|
$uri = bluesky_fetch_missing_post($uri, $item['uid'], $fetch_uid, Item::PR_FETCHED, $item['contact-id'], $level, $last_poll);
|
||||||
if ($uri) {
|
if ($uri) {
|
||||||
$shared = Post::selectFirst(['uri-id'], ['uri' => $uri, 'uid' => [$item['uid'], 0]]);
|
$shared = Post::selectFirst(['uri-id'], ['uri' => $uri, 'uid' => [$item['uid'], 0]]);
|
||||||
|
@ -1439,6 +1519,30 @@ function bluesky_add_media(stdClass $embed, array $item, int $fetch_uid, int $le
|
||||||
return $item;
|
return $item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function bluesky_add_starterpack(array $item, stdClass $record)
|
||||||
|
{
|
||||||
|
Logger::debug('Received starterpack', ['uri-id' => $item['uri-id'], 'guid' => $item['guid'], 'uri' => $record->uri]);
|
||||||
|
if (!preg_match('#^at://(.+)/app.bsky.graph.starterpack/(.+)#', $record->uri, $matches)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$media = [
|
||||||
|
'uri-id' => $item['uri-id'],
|
||||||
|
'type' => Post\Media::HTML,
|
||||||
|
'url' => 'https://bsky.app/starter-pack/' . $matches[1] . '/' . $matches[2],
|
||||||
|
'name' => $record->record->name,
|
||||||
|
'description' => $record->record->description,
|
||||||
|
];
|
||||||
|
|
||||||
|
Post\Media::insert($media);
|
||||||
|
|
||||||
|
$fields = [
|
||||||
|
'name' => $record->record->name,
|
||||||
|
'description' => $record->record->description,
|
||||||
|
];
|
||||||
|
Post\Media::update($fields, ['uri-id' => $media['uri-id'], 'url' => $media['url']]);
|
||||||
|
}
|
||||||
|
|
||||||
function bluesky_get_uri(stdClass $post): string
|
function bluesky_get_uri(stdClass $post): string
|
||||||
{
|
{
|
||||||
if (empty($post->cid)) {
|
if (empty($post->cid)) {
|
||||||
|
@ -1491,10 +1595,10 @@ function bluesky_get_uri_parts(string $uri): ?stdClass
|
||||||
return $class;
|
return $class;
|
||||||
}
|
}
|
||||||
|
|
||||||
function bluesky_fetch_missing_post(string $uri, int $uid, int $fetch_uid, int $post_reason, int $causer, int $level, int $last_poll, string $fallback = ''): string
|
function bluesky_fetch_missing_post(string $uri, int $uid, int $fetch_uid, int $post_reason, int $causer, int $level, int $last_poll, string $fallback = '', bool $always_fetch = false): string
|
||||||
{
|
{
|
||||||
$fetched_uri = bluesky_fetch_post($uri, $uid);
|
$fetched_uri = bluesky_fetch_post($uri, $uid);
|
||||||
if (!empty($fetched_uri)) {
|
if (!$always_fetch && !empty($fetched_uri)) {
|
||||||
return $fetched_uri;
|
return $fetched_uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1514,7 +1618,7 @@ function bluesky_fetch_missing_post(string $uri, int $uid, int $fetch_uid, int $
|
||||||
|
|
||||||
Logger::debug('Fetch missing post', ['level' => $level, 'uid' => $uid, 'uri' => $uri]);
|
Logger::debug('Fetch missing post', ['level' => $level, 'uid' => $uid, 'uri' => $uri]);
|
||||||
$data = bluesky_xrpc_get($fetch_uid, 'app.bsky.feed.getPostThread', ['uri' => $fetch_uri]);
|
$data = bluesky_xrpc_get($fetch_uid, 'app.bsky.feed.getPostThread', ['uri' => $fetch_uri]);
|
||||||
if (empty($data)) {
|
if (empty($data) || empty($data->thread)) {
|
||||||
Logger::info('Thread was not fetched', ['level' => $level, 'uid' => $uid, 'uri' => $uri, 'fallback' => $fallback]);
|
Logger::info('Thread was not fetched', ['level' => $level, 'uid' => $uid, 'uri' => $uri, 'fallback' => $fallback]);
|
||||||
return $fallback;
|
return $fallback;
|
||||||
}
|
}
|
||||||
|
@ -1522,13 +1626,34 @@ function bluesky_fetch_missing_post(string $uri, int $uid, int $fetch_uid, int $
|
||||||
Logger::debug('Reply count', ['level' => $level, 'uid' => $uid, 'uri' => $uri]);
|
Logger::debug('Reply count', ['level' => $level, 'uid' => $uid, 'uri' => $uri]);
|
||||||
|
|
||||||
if ($causer != 0) {
|
if ($causer != 0) {
|
||||||
$cdata = Contact::getPublicAndUserContactID($causer, $uid);
|
$causer = Contact::getPublicContactId($causer, $uid);
|
||||||
$causer = $cdata['public'] ?? 0;
|
}
|
||||||
|
|
||||||
|
if (!empty($data->thread->parent)) {
|
||||||
|
$parents = bluesky_fetch_parents($data->thread->parent, $uid);
|
||||||
|
|
||||||
|
foreach ($parents as $parent) {
|
||||||
|
$uri_id = bluesky_process_post($parent, $uid, $fetch_uid, Item::PR_FETCHED, $causer, $level, $last_poll);
|
||||||
|
Logger::debug('Parent created', ['uri-id' => $uri_id]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return bluesky_process_thread($data->thread, $uid, $fetch_uid, $post_reason, $causer, $level, $last_poll);
|
return bluesky_process_thread($data->thread, $uid, $fetch_uid, $post_reason, $causer, $level, $last_poll);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function bluesky_fetch_parents(stdClass $parent, int $uid, array $parents = []): array
|
||||||
|
{
|
||||||
|
if (!empty($parent->parent)) {
|
||||||
|
$parents = bluesky_fetch_parents($parent->parent, $uid, $parents);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($parent->post) && empty(bluesky_fetch_post(bluesky_get_uri($parent->post), $uid))) {
|
||||||
|
$parents[] = $parent->post;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $parents;
|
||||||
|
}
|
||||||
|
|
||||||
function bluesky_fetch_post(string $uri, int $uid): string
|
function bluesky_fetch_post(string $uri, int $uid): string
|
||||||
{
|
{
|
||||||
if (Post::exists(['uri' => $uri, 'uid' => [$uid, 0]])) {
|
if (Post::exists(['uri' => $uri, 'uid' => [$uid, 0]])) {
|
||||||
|
@ -1592,7 +1717,7 @@ function bluesky_process_thread(stdClass $thread, int $uid, int $fetch_uid, int
|
||||||
|
|
||||||
function bluesky_get_contact(stdClass $author, int $uid, int $fetch_uid): array
|
function bluesky_get_contact(stdClass $author, int $uid, int $fetch_uid): array
|
||||||
{
|
{
|
||||||
$condition = ['network' => Protocol::BLUESKY, 'uid' => 0, 'url' => $author->did];
|
$condition = ['network' => Protocol::BLUESKY, 'uid' => 0, 'nurl' => $author->did];
|
||||||
$contact = Contact::selectFirst(['id', 'updated'], $condition);
|
$contact = Contact::selectFirst(['id', 'updated'], $condition);
|
||||||
|
|
||||||
$update = empty($contact) || $contact['updated'] < DateTimeFormat::utc('now -24 hours');
|
$update = empty($contact) || $contact['updated'] < DateTimeFormat::utc('now -24 hours');
|
||||||
|
@ -1610,7 +1735,7 @@ function bluesky_get_contact(stdClass $author, int $uid, int $fetch_uid): array
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($uid != 0) {
|
if ($uid != 0) {
|
||||||
$condition = ['network' => Protocol::BLUESKY, 'uid' => $uid, 'url' => $author->did];
|
$condition = ['network' => Protocol::BLUESKY, 'uid' => $uid, 'nurl' => $author->did];
|
||||||
|
|
||||||
$contact = Contact::selectFirst(['id', 'rel', 'uid'], $condition);
|
$contact = Contact::selectFirst(['id', 'rel', 'uid'], $condition);
|
||||||
if (!isset($fields['rel']) && isset($contact['rel'])) {
|
if (!isset($fields['rel']) && isset($contact['rel'])) {
|
||||||
|
@ -1663,10 +1788,14 @@ function bluesky_get_contact_fields(stdClass $author, int $uid, int $fetch_uid,
|
||||||
return $fields;
|
return $fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
$fields['baseurl'] = bluesky_get_pds($author->did);
|
$data = bluesky_get(BLUESKY_DIRECTORY . '/' . $author->did);
|
||||||
if (!empty($fields['baseurl'])) {
|
if (!empty($data)) {
|
||||||
GServer::check($fields['baseurl'], Protocol::BLUESKY);
|
$fields['baseurl'] = bluesky_get_pds('', $data);
|
||||||
$fields['gsid'] = GServer::getID($fields['baseurl'], true);
|
if (!empty($fields['baseurl'])) {
|
||||||
|
GServer::check($fields['baseurl'], Protocol::BLUESKY);
|
||||||
|
$fields['gsid'] = GServer::getID($fields['baseurl'], true);
|
||||||
|
}
|
||||||
|
$fields['pubkey'] = bluesky_get_public_key('', $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = bluesky_xrpc_get($fetch_uid, 'app.bsky.actor.getProfile', ['actor' => $author->did]);
|
$data = bluesky_xrpc_get($fetch_uid, 'app.bsky.actor.getProfile', ['actor' => $author->did]);
|
||||||
|
@ -1705,6 +1834,9 @@ function bluesky_get_feeds(int $uid): array
|
||||||
{
|
{
|
||||||
$type = '$type';
|
$type = '$type';
|
||||||
$preferences = bluesky_get_preferences($uid);
|
$preferences = bluesky_get_preferences($uid);
|
||||||
|
if (empty($preferences) || empty($preferences->preferences)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
foreach ($preferences->preferences as $preference) {
|
foreach ($preferences->preferences as $preference) {
|
||||||
if ($preference->$type == 'app.bsky.actor.defs#savedFeedsPref') {
|
if ($preference->$type == 'app.bsky.actor.defs#savedFeedsPref') {
|
||||||
return $preference->pinned ?? [];
|
return $preference->pinned ?? [];
|
||||||
|
@ -1713,7 +1845,7 @@ function bluesky_get_feeds(int $uid): array
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
function bluesky_get_preferences(int $uid): stdClass
|
function bluesky_get_preferences(int $uid): ?stdClass
|
||||||
{
|
{
|
||||||
$cachekey = 'bluesky:preferences:' . $uid;
|
$cachekey = 'bluesky:preferences:' . $uid;
|
||||||
$data = DI::cache()->get($cachekey);
|
$data = DI::cache()->get($cachekey);
|
||||||
|
@ -1722,11 +1854,63 @@ function bluesky_get_preferences(int $uid): stdClass
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = bluesky_xrpc_get($uid, 'app.bsky.actor.getPreferences');
|
$data = bluesky_xrpc_get($uid, 'app.bsky.actor.getPreferences');
|
||||||
|
if (empty($data)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
DI::cache()->set($cachekey, $data, Duration::HOUR);
|
DI::cache()->set($cachekey, $data, Duration::HOUR);
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function bluesky_get_did_by_profile(string $url, int $uid): string
|
||||||
|
{
|
||||||
|
if (preg_match('#^' . BLUESKY_WEB . '/profile/(.+)#', $url, $matches)) {
|
||||||
|
$did = bluesky_get_did($matches[1], $uid);
|
||||||
|
if (!empty($did)) {
|
||||||
|
return $did;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$curlResult = DI::httpClient()->get($url, HttpClientAccept::HTML, [HttpClientOptions::REQUEST => HttpClientRequest::CONTACTINFO]);
|
||||||
|
} catch (\Throwable $th) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
if (!$curlResult->isSuccess()) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
$profile = $curlResult->getBodyString();
|
||||||
|
if (empty($profile)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$doc = new DOMDocument();
|
||||||
|
try {
|
||||||
|
@$doc->loadHTML($profile);
|
||||||
|
} catch (\Throwable $th) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
$xpath = new DOMXPath($doc);
|
||||||
|
$list = $xpath->query('//p[@id]');
|
||||||
|
foreach ($list as $node) {
|
||||||
|
foreach ($node->attributes as $attribute) {
|
||||||
|
if ($attribute->name == 'id') {
|
||||||
|
$ids[$attribute->value] = $node->textContent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($ids['bsky_handle']) || empty($ids['bsky_did'])) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bluesky_valid_did($ids['bsky_did'], $ids['bsky_handle'])) {
|
||||||
|
Logger::notice('Invalid DID', ['handle' => $ids['bsky_handle'], 'did' => $ids['bsky_did']]);
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ids['bsky_did'];
|
||||||
|
}
|
||||||
|
|
||||||
function bluesky_get_did_by_wellknown(string $handle): string
|
function bluesky_get_did_by_wellknown(string $handle): string
|
||||||
{
|
{
|
||||||
$curlResult = DI::httpClient()->get('http://' . $handle . '/.well-known/atproto-did');
|
$curlResult = DI::httpClient()->get('http://' . $handle . '/.well-known/atproto-did');
|
||||||
|
@ -1736,7 +1920,6 @@ function bluesky_get_did_by_wellknown(string $handle): string
|
||||||
Logger::notice('Invalid DID', ['handle' => $handle, 'did' => $did]);
|
Logger::notice('Invalid DID', ['handle' => $handle, 'did' => $did]);
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
Logger::debug('Got DID by wellknown', ['handle' => $handle, 'did' => $did]);
|
|
||||||
return $did;
|
return $did;
|
||||||
}
|
}
|
||||||
return '';
|
return '';
|
||||||
|
@ -1755,32 +1938,55 @@ function bluesky_get_did_by_dns(string $handle): string
|
||||||
Logger::notice('Invalid DID', ['handle' => $handle, 'did' => $did]);
|
Logger::notice('Invalid DID', ['handle' => $handle, 'did' => $did]);
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
Logger::debug('Got DID by DNS', ['handle' => $handle, 'did' => $did]);
|
|
||||||
return $did;
|
return $did;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
function bluesky_get_did(string $handle): string
|
function bluesky_get_did(string $handle, int $uid): string
|
||||||
{
|
{
|
||||||
// Deactivated at the moment, since it isn't reliable by now
|
if ($handle == '') {
|
||||||
//$did = bluesky_get_did_by_dns($handle);
|
|
||||||
//if ($did != '') {
|
|
||||||
// return $did;
|
|
||||||
//}
|
|
||||||
|
|
||||||
//$did = bluesky_get_did_by_wellknown($handle);
|
|
||||||
//if ($did != '') {
|
|
||||||
// return $did;
|
|
||||||
//}
|
|
||||||
|
|
||||||
$data = bluesky_get(BLUESKY_PDS . '/xrpc/com.atproto.identity.resolveHandle?handle=' . urlencode($handle));
|
|
||||||
if (empty($data) || empty($data->did)) {
|
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
Logger::debug('Got DID by PDS call', ['handle' => $handle, 'did' => $data->did]);
|
|
||||||
return $data->did;
|
if (strpos($handle, '.') === false) {
|
||||||
|
$handle .= '.' . BLUESKY_HOSTNAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
// At first we use the user PDS. That should cover most cases.
|
||||||
|
$pds = DI::pConfig()->get($uid, 'bluesky', 'pds');
|
||||||
|
if (!empty($pds)) {
|
||||||
|
$data = bluesky_get($pds . '/xrpc/com.atproto.identity.resolveHandle?handle=' . urlencode($handle));
|
||||||
|
if (!empty($data) && !empty($data->did)) {
|
||||||
|
Logger::debug('Got DID by user PDS call', ['handle' => $handle, 'did' => $data->did]);
|
||||||
|
return $data->did;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then we query the DNS, which is used for third party handles (DNS should be faster than wellknown)
|
||||||
|
$did = bluesky_get_did_by_dns($handle);
|
||||||
|
if ($did != '') {
|
||||||
|
Logger::debug('Got DID by DNS', ['handle' => $handle, 'did' => $did]);
|
||||||
|
return $did;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then we query wellknown, which should mostly cover the rest.
|
||||||
|
$did = bluesky_get_did_by_wellknown($handle);
|
||||||
|
if ($did != '') {
|
||||||
|
Logger::debug('Got DID by wellknown', ['handle' => $handle, 'did' => $did]);
|
||||||
|
return $did;
|
||||||
|
}
|
||||||
|
|
||||||
|
// And finally we use the default PDS from Bluesky.
|
||||||
|
$data = bluesky_get(BLUESKY_PDS . '/xrpc/com.atproto.identity.resolveHandle?handle=' . urlencode($handle));
|
||||||
|
if (!empty($data) && !empty($data->did)) {
|
||||||
|
Logger::debug('Got DID by system PDS call', ['handle' => $handle, 'did' => $data->did]);
|
||||||
|
return $data->did;
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger::notice('No DID detected', ['handle' => $handle]);
|
||||||
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
function bluesky_get_user_did(int $uid, bool $refresh = false): ?string
|
function bluesky_get_user_did(int $uid, bool $refresh = false): ?string
|
||||||
|
@ -1797,7 +2003,7 @@ function bluesky_get_user_did(int $uid, bool $refresh = false): ?string
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$did = bluesky_get_did($handle);
|
$did = bluesky_get_did($handle, $uid);
|
||||||
if (empty($did)) {
|
if (empty($did)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -1828,9 +2034,11 @@ function bluesky_get_user_pds(int $uid): ?string
|
||||||
return $pds;
|
return $pds;
|
||||||
}
|
}
|
||||||
|
|
||||||
function bluesky_get_pds(string $did): ?string
|
function bluesky_get_pds(string $did, stdClass $data = null): ?string
|
||||||
{
|
{
|
||||||
$data = bluesky_get(BLUESKY_DIRECTORY . '/' . $did);
|
if (empty($data)) {
|
||||||
|
$data = bluesky_get(BLUESKY_DIRECTORY . '/' . $did);
|
||||||
|
}
|
||||||
if (empty($data) || empty($data->service)) {
|
if (empty($data) || empty($data->service)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -1844,6 +2052,22 @@ function bluesky_get_pds(string $did): ?string
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function bluesky_get_public_key(string $did, stdClass $data = null): ?string
|
||||||
|
{
|
||||||
|
if (empty($data)) {
|
||||||
|
$data = bluesky_get(BLUESKY_DIRECTORY . '/' . $did);
|
||||||
|
}
|
||||||
|
if (empty($data) || empty($data->verificationMethod)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
foreach ($data->verificationMethod as $method) {
|
||||||
|
if (!empty($method->publicKeyMultibase)) {
|
||||||
|
return $method->publicKeyMultibase;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
function bluesky_valid_did(string $did, string $handle): bool
|
function bluesky_valid_did(string $did, string $handle): bool
|
||||||
{
|
{
|
||||||
$data = bluesky_get(BLUESKY_DIRECTORY . '/' . $did);
|
$data = bluesky_get(BLUESKY_DIRECTORY . '/' . $did);
|
||||||
|
@ -1873,7 +2097,7 @@ function bluesky_refresh_token(int $uid): string
|
||||||
$token = DI::pConfig()->get($uid, 'bluesky', 'refresh_token');
|
$token = DI::pConfig()->get($uid, 'bluesky', 'refresh_token');
|
||||||
|
|
||||||
$data = bluesky_post($uid, '/xrpc/com.atproto.server.refreshSession', '', ['Authorization' => ['Bearer ' . $token]]);
|
$data = bluesky_post($uid, '/xrpc/com.atproto.server.refreshSession', '', ['Authorization' => ['Bearer ' . $token]]);
|
||||||
if (empty($data)) {
|
if (empty($data) || empty($data->accessJwt)) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1892,7 +2116,7 @@ function bluesky_create_token(int $uid, string $password): string
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = bluesky_post($uid, '/xrpc/com.atproto.server.createSession', json_encode(['identifier' => $did, 'password' => $password]), ['Content-type' => 'application/json']);
|
$data = bluesky_post($uid, '/xrpc/com.atproto.server.createSession', json_encode(['identifier' => $did, 'password' => $password]), ['Content-type' => 'application/json']);
|
||||||
if (empty($data)) {
|
if (empty($data) || empty($data->accessJwt)) {
|
||||||
DI::pConfig()->set($uid, 'bluesky', 'status', BLUEKSY_STATUS_TOKEN_FAIL);
|
DI::pConfig()->set($uid, 'bluesky', 'status', BLUEKSY_STATUS_TOKEN_FAIL);
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
@ -1907,7 +2131,11 @@ function bluesky_create_token(int $uid, string $password): string
|
||||||
|
|
||||||
function bluesky_xrpc_post(int $uid, string $url, $parameters): ?stdClass
|
function bluesky_xrpc_post(int $uid, string $url, $parameters): ?stdClass
|
||||||
{
|
{
|
||||||
return bluesky_post($uid, '/xrpc/' . $url, json_encode($parameters), ['Content-type' => 'application/json', 'Authorization' => ['Bearer ' . bluesky_get_token($uid)]]);
|
$data = bluesky_post($uid, '/xrpc/' . $url, json_encode($parameters), ['Content-type' => 'application/json', 'Authorization' => ['Bearer ' . bluesky_get_token($uid)]]);
|
||||||
|
if (!empty($data)) {
|
||||||
|
Item::incrementOutbound(Protocol::BLUESKY);
|
||||||
|
}
|
||||||
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
function bluesky_post(int $uid, string $url, string $params, array $headers): ?stdClass
|
function bluesky_post(int $uid, string $url, string $params, array $headers): ?stdClass
|
||||||
|
@ -1925,14 +2153,18 @@ function bluesky_post(int $uid, string $url, string $params, array $headers): ?s
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$data = json_decode($curlResult->getBodyString());
|
||||||
if (!$curlResult->isSuccess()) {
|
if (!$curlResult->isSuccess()) {
|
||||||
Logger::notice('API Error', ['error' => json_decode($curlResult->getBodyString()) ?: $curlResult->getBodyString()]);
|
Logger::notice('API Error', ['url' => $url, 'code' => $curlResult->getReturnCode(), 'error' => $data ?: $curlResult->getBodyString()]);
|
||||||
DI::pConfig()->set($uid, 'bluesky', 'status', BLUEKSY_STATUS_API_FAIL);
|
if (!$data) {
|
||||||
return null;
|
DI::pConfig()->set($uid, 'bluesky', 'status', BLUEKSY_STATUS_API_FAIL);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$data->code = $curlResult->getReturnCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
DI::pConfig()->set($uid, 'bluesky', 'status', BLUEKSY_STATUS_SUCCESS);
|
DI::pConfig()->set($uid, 'bluesky', 'status', BLUEKSY_STATUS_SUCCESS);
|
||||||
return json_decode($curlResult->getBodyString());
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
function bluesky_xrpc_get(int $uid, string $url, array $parameters = []): ?stdClass
|
function bluesky_xrpc_get(int $uid, string $url, array $parameters = []): ?stdClass
|
||||||
|
@ -1946,7 +2178,14 @@ function bluesky_xrpc_get(int $uid, string $url, array $parameters = []): ?stdCl
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = bluesky_get($pds . '/xrpc/' . $url, HttpClientAccept::JSON, [HttpClientOptions::HEADERS => ['Authorization' => ['Bearer ' . bluesky_get_token($uid)]]]);
|
$headers = ['Authorization' => ['Bearer ' . bluesky_get_token($uid)]];
|
||||||
|
|
||||||
|
$languages = User::getWantedLanguages($uid);
|
||||||
|
if (!empty($languages)) {
|
||||||
|
$headers['Accept-Language'] = implode(',', $languages);
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = bluesky_get($pds . '/xrpc/' . $url, HttpClientAccept::JSON, [HttpClientOptions::HEADERS => $headers]);
|
||||||
DI::pConfig()->set($uid, 'bluesky', 'status', is_null($data) ? BLUEKSY_STATUS_API_FAIL : BLUEKSY_STATUS_SUCCESS);
|
DI::pConfig()->set($uid, 'bluesky', 'status', is_null($data) ? BLUEKSY_STATUS_API_FAIL : BLUEKSY_STATUS_SUCCESS);
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
@ -1960,10 +2199,15 @@ function bluesky_get(string $url, string $accept_content = HttpClientAccept::DEF
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$data = json_decode($curlResult->getBodyString());
|
||||||
if (!$curlResult->isSuccess()) {
|
if (!$curlResult->isSuccess()) {
|
||||||
Logger::notice('API Error', ['url' => $url, 'error' => json_decode($curlResult->getBodyString()) ?: $curlResult->getBodyString()]);
|
Logger::notice('API Error', ['url' => $url, 'code' => $curlResult->getReturnCode(), 'error' => $data ?: $curlResult->getBodyString()]);
|
||||||
return null;
|
if (!$data) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$data->code = $curlResult->getReturnCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
return json_decode($curlResult->getBodyString());
|
Item::incrementInbound(Protocol::BLUESKY);
|
||||||
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,11 +6,11 @@ function bluesky_feed_run($argv, $argc)
|
||||||
{
|
{
|
||||||
require_once 'addon/bluesky/bluesky.php';
|
require_once 'addon/bluesky/bluesky.php';
|
||||||
|
|
||||||
if ($argc != 4) {
|
if ($argc < 3) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger::debug('Importing feed - start', ['user' => $argv[1], 'feed' => $argv[2], 'last_poll' => $argv[3]]);
|
Logger::debug('Importing feed - start', ['user' => $argv[1], 'feed' => $argv[2]]);
|
||||||
bluesky_fetch_feed($argv[1], $argv[2], $argv[3]);
|
bluesky_fetch_feed($argv[1], $argv[2]);
|
||||||
Logger::debug('Importing feed - done', ['user' => $argv[1], 'feed' => $argv[2], 'last_poll' => $argv[3]]);
|
Logger::debug('Importing feed - done', ['user' => $argv[1], 'feed' => $argv[2]]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,11 +6,11 @@ function bluesky_notifications_run($argv, $argc)
|
||||||
{
|
{
|
||||||
require_once 'addon/bluesky/bluesky.php';
|
require_once 'addon/bluesky/bluesky.php';
|
||||||
|
|
||||||
if ($argc != 3) {
|
if ($argc < 2) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger::notice('importing notifications - start', ['user' => $argv[1], 'last_poll' => $argv[2]]);
|
Logger::notice('importing notifications - start', ['user' => $argv[1]]);
|
||||||
bluesky_fetch_notifications($argv[1], $argv[2]);
|
bluesky_fetch_notifications($argv[1]);
|
||||||
Logger::notice('importing notifications - done', ['user' => $argv[1], 'last_poll' => $argv[2]]);
|
Logger::notice('importing notifications - done', ['user' => $argv[1]]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,11 +6,11 @@ function bluesky_timeline_run($argv, $argc)
|
||||||
{
|
{
|
||||||
require_once 'addon/bluesky/bluesky.php';
|
require_once 'addon/bluesky/bluesky.php';
|
||||||
|
|
||||||
if ($argc != 3) {
|
if ($argc < 2) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger::notice('importing timeline - start', ['user' => $argv[1], 'last_poll' => $argv[2]]);
|
Logger::notice('importing timeline - start', ['user' => $argv[1]]);
|
||||||
bluesky_fetch_timeline($argv[1], $argv[2]);
|
bluesky_fetch_timeline($argv[1]);
|
||||||
Logger::notice('importing timeline - done', ['user' => $argv[1], 'last_poll' => $argv[2]]);
|
Logger::notice('importing timeline - done', ['user' => $argv[1]]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: \n"
|
"Project-Id-Version: \n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2024-03-22 05:31+0000\n"
|
"POT-Creation-Date: 2024-09-29 18:16+0000\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
@ -17,131 +17,117 @@ msgstr ""
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
|
||||||
#: bluesky.php:325
|
#: bluesky.php:335
|
||||||
msgid "Save Settings"
|
msgid "Save Settings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: bluesky.php:326
|
#: bluesky.php:336
|
||||||
msgid "Allow your users to use your hostname for their Bluesky handles"
|
msgid "Allow your users to use your hostname for their Bluesky handles"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: bluesky.php:326
|
#: bluesky.php:336
|
||||||
#, php-format
|
#, php-format
|
||||||
msgid ""
|
msgid "Before enabling this option, you have to setup a wildcard domain configuration and you have to enable wildcard requests in your webserver configuration. On Apache this is done by adding \"ServerAlias *.%s\" to your HTTP configuration. You don't need to change the HTTPS configuration."
|
||||||
"Before enabling this option, you have to setup a wildcard domain "
|
|
||||||
"configuration and you have to enable wildcard requests in your webserver "
|
|
||||||
"configuration. On Apache this is done by adding \"ServerAlias *.%s\" to your "
|
|
||||||
"HTTP configuration. You don't need to change the HTTPS configuration."
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: bluesky.php:354
|
#: bluesky.php:365
|
||||||
#, php-format
|
#, php-format
|
||||||
msgid "Allow to use %s as your Bluesky handle."
|
msgid "Allow to use %s as your Bluesky handle."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: bluesky.php:354
|
#: bluesky.php:365
|
||||||
#, php-format
|
#, php-format
|
||||||
msgid ""
|
msgid "When enabled, you can use %s as your Bluesky handle. After you enabled this option, please go to https://bsky.app/settings and select to change your handle. Select that you have got your own domain. Then enter %s and select \"No DNS Panel\". Then select \"Verify Text File\"."
|
||||||
"When enabled, you can use %s as your Bluesky handle. After you enabled this "
|
|
||||||
"option, please go to https://bsky.app/settings and select to change your "
|
|
||||||
"handle. Select that you have got your own domain. Then enter %s and select "
|
|
||||||
"\"No DNS Panel\". Then select \"Verify Text File\"."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: bluesky.php:361
|
|
||||||
msgid "Enable Bluesky Post Addon"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: bluesky.php:362
|
|
||||||
msgid "Post to Bluesky by default"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: bluesky.php:363
|
|
||||||
msgid "Import the remote timeline"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: bluesky.php:364
|
|
||||||
msgid "Import the pinned feeds"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: bluesky.php:364
|
|
||||||
msgid ""
|
|
||||||
"When activated, Posts will be imported from all the feeds that you pinned in "
|
|
||||||
"Bluesky."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: bluesky.php:366
|
|
||||||
msgid "Personal Data Server"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: bluesky.php:366
|
|
||||||
msgid "The personal data server (PDS) is the system that hosts your profile."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: bluesky.php:367
|
|
||||||
msgid "Bluesky handle"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: bluesky.php:368
|
|
||||||
msgid "Bluesky DID"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: bluesky.php:368
|
|
||||||
msgid ""
|
|
||||||
"This is the unique identifier. It will be fetched automatically, when the "
|
|
||||||
"handle is entered."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: bluesky.php:369
|
|
||||||
msgid "Bluesky app password"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: bluesky.php:369
|
|
||||||
msgid ""
|
|
||||||
"Please don't add your real password here, but instead create a specific app "
|
|
||||||
"password in the Bluesky settings."
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: bluesky.php:375
|
#: bluesky.php:375
|
||||||
|
msgid "Enable Bluesky Post Addon"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: bluesky.php:376
|
||||||
|
msgid "Post to Bluesky by default"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: bluesky.php:377
|
||||||
|
msgid "Import the remote timeline"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: bluesky.php:378
|
||||||
|
msgid "Import the pinned feeds"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: bluesky.php:378
|
||||||
|
msgid "When activated, Posts will be imported from all the feeds that you pinned in Bluesky."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: bluesky.php:379
|
||||||
|
msgid "Complete the threads"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: bluesky.php:379
|
||||||
|
msgid "When activated, the system fetches additional replies for the posts in the timeline. This leads to more complete threads."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: bluesky.php:381
|
||||||
|
msgid "Personal Data Server"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: bluesky.php:381
|
||||||
|
msgid "The personal data server (PDS) is the system that hosts your profile."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: bluesky.php:382
|
||||||
|
msgid "Bluesky handle"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: bluesky.php:383
|
||||||
|
msgid "Bluesky DID"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: bluesky.php:383
|
||||||
|
msgid "This is the unique identifier. It will be fetched automatically, when the handle is entered."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: bluesky.php:384
|
||||||
|
msgid "Bluesky app password"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: bluesky.php:384
|
||||||
|
msgid "Please don't add your real password here, but instead create a specific app password in the Bluesky settings."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: bluesky.php:390
|
||||||
msgid "Bluesky Import/Export"
|
msgid "Bluesky Import/Export"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: bluesky.php:385
|
#: bluesky.php:400
|
||||||
msgid ""
|
msgid "You are not authenticated. Please enter your handle and the app password."
|
||||||
"You are not authenticated. Please enter your handle and the app password."
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: bluesky.php:405
|
#: bluesky.php:420
|
||||||
msgid ""
|
msgid "You are authenticated to Bluesky. For security reasons the password isn't stored."
|
||||||
"You are authenticated to Bluesky. For security reasons the password isn't "
|
|
||||||
"stored."
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: bluesky.php:407
|
#: bluesky.php:422
|
||||||
msgid ""
|
msgid "The communication with the personal data server service (PDS) is established."
|
||||||
"The communication with the personal data server service (PDS) is established."
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: bluesky.php:409
|
#: bluesky.php:424
|
||||||
msgid "Communication issues with the personal data server service (PDS)."
|
msgid "Communication issues with the personal data server service (PDS)."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: bluesky.php:411
|
#: bluesky.php:426
|
||||||
msgid ""
|
msgid "The DID for the provided handle could not be detected. Please check if you entered the correct handle."
|
||||||
"The DID for the provided handle could not be detected. Please check if you "
|
|
||||||
"entered the correct handle."
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: bluesky.php:413
|
#: bluesky.php:428
|
||||||
msgid "The personal data server service (PDS) could not be detected."
|
msgid "The personal data server service (PDS) could not be detected."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: bluesky.php:415
|
#: bluesky.php:430
|
||||||
msgid ""
|
msgid "The authentication with the provided handle and password failed. Please check if you entered the correct password."
|
||||||
"The authentication with the provided handle and password failed. Please "
|
|
||||||
"check if you entered the correct password."
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: bluesky.php:484
|
#: bluesky.php:492
|
||||||
msgid "Post to Bluesky"
|
msgid "Post to Bluesky"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
{{include file="field_checkbox.tpl" field=$bydefault}}
|
{{include file="field_checkbox.tpl" field=$bydefault}}
|
||||||
{{include file="field_checkbox.tpl" field=$import}}
|
{{include file="field_checkbox.tpl" field=$import}}
|
||||||
{{include file="field_checkbox.tpl" field=$import_feeds}}
|
{{include file="field_checkbox.tpl" field=$import_feeds}}
|
||||||
|
{{include file="field_checkbox.tpl" field=$complete_threads}}
|
||||||
{{if $custom_handle}}
|
{{if $custom_handle}}
|
||||||
{{include file="field_checkbox.tpl" field=$custom_handle}}
|
{{include file="field_checkbox.tpl" field=$custom_handle}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
|
@ -6,55 +6,55 @@
|
||||||
# Translators:
|
# Translators:
|
||||||
# fabrixxm <fabrix.xm@gmail.com>, 2018
|
# fabrixxm <fabrix.xm@gmail.com>, 2018
|
||||||
# Davide Pesenti <mrjive@mrjive.it>, 2018
|
# Davide Pesenti <mrjive@mrjive.it>, 2018
|
||||||
# Sylke Vicious <silkevicious@gmail.com>, 2021
|
# Sylke Vicious <silkevicious@gmail.com>, 2023
|
||||||
#
|
#
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: \n"
|
"Project-Id-Version: \n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2020-12-29 00:53+0000\n"
|
"POT-Creation-Date: 2021-11-21 19:14-0500\n"
|
||||||
"PO-Revision-Date: 2018-04-07 05:23+0000\n"
|
"PO-Revision-Date: 2018-04-07 05:23+0000\n"
|
||||||
"Last-Translator: Sylke Vicious <silkevicious@gmail.com>, 2021\n"
|
"Last-Translator: Sylke Vicious <silkevicious@gmail.com>, 2023\n"
|
||||||
"Language-Team: Italian (https://www.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"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Language: it\n"
|
"Language: it\n"
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
"Plural-Forms: nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n"
|
||||||
|
|
||||||
#: catavatar.php:48
|
#: catavatar.php:48
|
||||||
msgid "Use Cat as Avatar"
|
|
||||||
msgstr "Usa il Gatto come avatar"
|
|
||||||
|
|
||||||
#: catavatar.php:49
|
|
||||||
msgid "More Random Cat!"
|
|
||||||
msgstr "Altro Gatto a caso!"
|
|
||||||
|
|
||||||
#: catavatar.php:50
|
|
||||||
msgid "Reset to email Cat"
|
|
||||||
msgstr "Reimposta Gatto"
|
|
||||||
|
|
||||||
#: catavatar.php:52
|
|
||||||
msgid "Cat Avatar Settings"
|
|
||||||
msgstr "Impostazioni Avatar Gatto"
|
|
||||||
|
|
||||||
#: catavatar.php:53
|
|
||||||
msgid "Set default profile avatar or randomize the cat."
|
msgid "Set default profile avatar or randomize the cat."
|
||||||
msgstr "Imposta l'immagine di profilo predefinita o crea un gatto casuale."
|
msgstr "Imposta l'immagine di profilo predefinita o crea un gatto casuale."
|
||||||
|
|
||||||
#: catavatar.php:78
|
#: catavatar.php:53
|
||||||
|
msgid "Cat Avatar Settings"
|
||||||
|
msgstr "Impostazioni Avatar Gatto"
|
||||||
|
|
||||||
|
#: catavatar.php:56
|
||||||
|
msgid "Use Cat as Avatar"
|
||||||
|
msgstr "Usa il Gatto come avatar"
|
||||||
|
|
||||||
|
#: catavatar.php:57
|
||||||
|
msgid "Another random Cat!"
|
||||||
|
msgstr "Un altro Gatto casuale!"
|
||||||
|
|
||||||
|
#: catavatar.php:58
|
||||||
|
msgid "Reset to email Cat"
|
||||||
|
msgstr "Reimposta Gatto"
|
||||||
|
|
||||||
|
#: catavatar.php:77
|
||||||
msgid "The cat hadn't found itself."
|
msgid "The cat hadn't found itself."
|
||||||
msgstr "Il gatto non ha trovato sé stesso."
|
msgstr "Il gatto non ha trovato sé stesso."
|
||||||
|
|
||||||
#: catavatar.php:87
|
#: catavatar.php:86
|
||||||
msgid "There was an error, the cat ran away."
|
msgid "There was an error, the cat ran away."
|
||||||
msgstr "Si è verificato un errore, il gatto è scappato."
|
msgstr "Si è verificato un errore, il gatto è scappato."
|
||||||
|
|
||||||
#: catavatar.php:93
|
#: catavatar.php:92
|
||||||
msgid "Profile Photos"
|
msgid "Profile Photos"
|
||||||
msgstr "Foto del profilo"
|
msgstr "Foto del profilo"
|
||||||
|
|
||||||
#: catavatar.php:108
|
#: catavatar.php:102
|
||||||
msgid "Meow!"
|
msgid "Meow!"
|
||||||
msgstr "Miao!"
|
msgstr "Miao!"
|
||||||
|
|
|
@ -3,13 +3,13 @@
|
||||||
if(! function_exists("string_plural_select_it")) {
|
if(! function_exists("string_plural_select_it")) {
|
||||||
function string_plural_select_it($n){
|
function string_plural_select_it($n){
|
||||||
$n = intval($n);
|
$n = intval($n);
|
||||||
return intval($n != 1);
|
if ($n == 1) { return 0; } else if ($n != 0 && $n % 1000000 == 0) { return 1; } else { return 2; }
|
||||||
}}
|
}}
|
||||||
$a->strings['Use Cat as Avatar'] = 'Usa il Gatto come avatar';
|
|
||||||
$a->strings['More Random Cat!'] = 'Altro Gatto a caso!';
|
|
||||||
$a->strings['Reset to email Cat'] = 'Reimposta Gatto';
|
|
||||||
$a->strings['Cat Avatar Settings'] = 'Impostazioni Avatar Gatto';
|
|
||||||
$a->strings['Set default profile avatar or randomize the cat.'] = 'Imposta l\'immagine di profilo predefinita o crea un gatto casuale.';
|
$a->strings['Set default profile avatar or randomize the cat.'] = 'Imposta l\'immagine di profilo predefinita o crea un gatto casuale.';
|
||||||
|
$a->strings['Cat Avatar Settings'] = 'Impostazioni Avatar Gatto';
|
||||||
|
$a->strings['Use Cat as Avatar'] = 'Usa il Gatto come avatar';
|
||||||
|
$a->strings['Another random Cat!'] = 'Un altro Gatto casuale!';
|
||||||
|
$a->strings['Reset to email Cat'] = 'Reimposta Gatto';
|
||||||
$a->strings['The cat hadn\'t found itself.'] = 'Il gatto non ha trovato sé stesso.';
|
$a->strings['The cat hadn\'t found itself.'] = 'Il gatto non ha trovato sé stesso.';
|
||||||
$a->strings['There was an error, the cat ran away.'] = 'Si è verificato un errore, il gatto è scappato.';
|
$a->strings['There was an error, the cat ran away.'] = 'Si è verificato un errore, il gatto è scappato.';
|
||||||
$a->strings['Profile Photos'] = 'Foto del profilo';
|
$a->strings['Profile Photos'] = 'Foto del profilo';
|
||||||
|
|
|
@ -152,7 +152,7 @@ function curweather_network_mod_init(string &$body)
|
||||||
|
|
||||||
function curweather_addon_settings_post($post)
|
function curweather_addon_settings_post($post)
|
||||||
{
|
{
|
||||||
if (!DI::userSession()->getLocalUserId() || empty($_POST['curweather-settings-submit'])) {
|
if (!DI::userSession()->getLocalUserId() || empty($_POST['curweather-submit'])) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#
|
#
|
||||||
# Translators:
|
# Translators:
|
||||||
# bob lebonche <lebonche@tutanota.com>, 2021
|
# bob lebonche <lebonche@tutanota.com>, 2021
|
||||||
|
# cracrayol, 2024
|
||||||
# Hypolite Petovan <hypolite@mrpetovan.com>, 2022
|
# Hypolite Petovan <hypolite@mrpetovan.com>, 2022
|
||||||
# Hypolite Petovan <hypolite@mrpetovan.com>, 2016
|
# Hypolite Petovan <hypolite@mrpetovan.com>, 2016
|
||||||
# ea1cd8241cb389ffb6f92bc6891eff5d_dc12308 <70dced5587d47e18d88f9298024d96f8_93383>, 2015
|
# ea1cd8241cb389ffb6f92bc6891eff5d_dc12308 <70dced5587d47e18d88f9298024d96f8_93383>, 2015
|
||||||
|
@ -15,8 +16,8 @@ msgstr ""
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2021-11-21 19:14-0500\n"
|
"POT-Creation-Date: 2021-11-21 19:14-0500\n"
|
||||||
"PO-Revision-Date: 2014-06-22 11:34+0000\n"
|
"PO-Revision-Date: 2014-06-22 11:34+0000\n"
|
||||||
"Last-Translator: Hypolite Petovan <hypolite@mrpetovan.com>, 2022\n"
|
"Last-Translator: cracrayol, 2024\n"
|
||||||
"Language-Team: French (http://www.transifex.com/Friendica/friendica/language/fr/)\n"
|
"Language-Team: French (http://app.transifex.com/Friendica/friendica/language/fr/)\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"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
@ -45,7 +46,7 @@ msgstr "Vent"
|
||||||
|
|
||||||
#: curweather.php:140
|
#: curweather.php:140
|
||||||
msgid "Last Updated"
|
msgid "Last Updated"
|
||||||
msgstr "Dernière mise-à-jour"
|
msgstr "Dernière mise à jour"
|
||||||
|
|
||||||
#: curweather.php:141
|
#: curweather.php:141
|
||||||
msgid "Data by"
|
msgid "Data by"
|
||||||
|
|
|
@ -10,7 +10,7 @@ $a->strings['Current Weather'] = 'Météo actuelle';
|
||||||
$a->strings['Relative Humidity'] = 'Humidité relative';
|
$a->strings['Relative Humidity'] = 'Humidité relative';
|
||||||
$a->strings['Pressure'] = 'Pression';
|
$a->strings['Pressure'] = 'Pression';
|
||||||
$a->strings['Wind'] = 'Vent';
|
$a->strings['Wind'] = 'Vent';
|
||||||
$a->strings['Last Updated'] = 'Dernière mise-à-jour';
|
$a->strings['Last Updated'] = 'Dernière mise à jour';
|
||||||
$a->strings['Data by'] = 'Données de';
|
$a->strings['Data by'] = 'Données de';
|
||||||
$a->strings['Show on map'] = 'Montrer sur la carte';
|
$a->strings['Show on map'] = 'Montrer sur la carte';
|
||||||
$a->strings['There was a problem accessing the weather data. But have a look'] = 'Une erreur est survenue lors de l\'accès aux données météo. Vous pouvez quand même jeter un oeil';
|
$a->strings['There was a problem accessing the weather data. But have a look'] = 'Une erreur est survenue lors de l\'accès aux données météo. Vous pouvez quand même jeter un oeil';
|
||||||
|
|
|
@ -5,27 +5,27 @@
|
||||||
#
|
#
|
||||||
# Translators:
|
# Translators:
|
||||||
# fabrixxm <fabrix.xm@gmail.com>, 2014-2015
|
# fabrixxm <fabrix.xm@gmail.com>, 2014-2015
|
||||||
# Sylke Vicious <silkevicious@gmail.com>, 2021
|
# Sylke Vicious <silkevicious@gmail.com>, 2021,2023
|
||||||
# Tobias Diekershoff <tobias.diekershoff@gmx.net>, 2016
|
# Tobias Diekershoff <tobias.diekershoff@gmx.net>, 2016
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: friendica\n"
|
"Project-Id-Version: friendica\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2021-02-01 18:15+0100\n"
|
"POT-Creation-Date: 2021-11-21 19:14-0500\n"
|
||||||
"PO-Revision-Date: 2021-02-16 12:57+0000\n"
|
"PO-Revision-Date: 2014-06-22 11:34+0000\n"
|
||||||
"Last-Translator: Sylke Vicious <silkevicious@gmail.com>\n"
|
"Last-Translator: Sylke Vicious <silkevicious@gmail.com>, 2021,2023\n"
|
||||||
"Language-Team: Italian (http://www.transifex.com/Friendica/friendica/language/it/)\n"
|
"Language-Team: Italian (http://app.transifex.com/Friendica/friendica/language/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"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Language: it\n"
|
"Language: it\n"
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
"Plural-Forms: nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n"
|
||||||
|
|
||||||
#: curweather.php:47
|
#: curweather.php:47
|
||||||
msgid "Error fetching weather data. Error was: "
|
msgid "Error fetching weather data. Error was: "
|
||||||
msgstr "Errore durante il recupero dei dati meteo. L'errore è stato:"
|
msgstr "Errore durante il recupero dei dati meteo. L'errore è stato:"
|
||||||
|
|
||||||
#: curweather.php:130 curweather.php:192
|
#: curweather.php:130
|
||||||
msgid "Current Weather"
|
msgid "Current Weather"
|
||||||
msgstr "Meteo"
|
msgstr "Meteo"
|
||||||
|
|
||||||
|
@ -61,66 +61,66 @@ msgstr "C'è stato un problema accedendo ai dati meteo, ma dai un'occhiata"
|
||||||
msgid "at OpenWeatherMap"
|
msgid "at OpenWeatherMap"
|
||||||
msgstr "a OpenWeatherMap"
|
msgstr "a OpenWeatherMap"
|
||||||
|
|
||||||
#: curweather.php:179
|
#: curweather.php:178
|
||||||
msgid "No APPID found, please contact your admin to obtain one."
|
msgid "No APPID found, please contact your admin to obtain one."
|
||||||
msgstr "APPID non trovata, contatta il tuo amministratore per averne una."
|
msgstr "APPID non trovata, contatta il tuo amministratore per averne una."
|
||||||
|
|
||||||
#: curweather.php:191 curweather.php:229
|
#: curweather.php:188
|
||||||
msgid "Save Settings"
|
|
||||||
msgstr "Salva Impostazioni"
|
|
||||||
|
|
||||||
#: curweather.php:192
|
|
||||||
msgid "Settings"
|
|
||||||
msgstr "Impostazioni"
|
|
||||||
|
|
||||||
#: curweather.php:194
|
|
||||||
msgid "Enter either the name of your location or the zip code."
|
msgid "Enter either the name of your location or the zip code."
|
||||||
msgstr "Inserisci il nome della tua posizione o il CAP"
|
msgstr "Inserisci il nome della tua posizione o il CAP"
|
||||||
|
|
||||||
#: curweather.php:195
|
#: curweather.php:189
|
||||||
msgid "Your Location"
|
msgid "Your Location"
|
||||||
msgstr "La tua Posizione"
|
msgstr "La tua Posizione"
|
||||||
|
|
||||||
#: curweather.php:195
|
#: curweather.php:189
|
||||||
msgid ""
|
msgid ""
|
||||||
"Identifier of your location (name or zip code), e.g. <em>Berlin,DE</em> or "
|
"Identifier of your location (name or zip code), e.g. <em>Berlin,DE</em> or "
|
||||||
"<em>14476,DE</em>."
|
"<em>14476,DE</em>."
|
||||||
msgstr "Identificatore della tua posizione (nome o CAP), p.e. <em>Roma, IT</em> or <em>00186,IT</em>."
|
msgstr "Identificatore della tua posizione (nome o CAP), p.e. <em>Roma, IT</em> or <em>00186,IT</em>."
|
||||||
|
|
||||||
#: curweather.php:196
|
#: curweather.php:190
|
||||||
msgid "Units"
|
msgid "Units"
|
||||||
msgstr "Unità"
|
msgstr "Unità"
|
||||||
|
|
||||||
#: curweather.php:196
|
#: curweather.php:190
|
||||||
msgid "select if the temperature should be displayed in °C or °F"
|
msgid "select if the temperature should be displayed in °C or °F"
|
||||||
msgstr "scegli se la temperatura deve essere mostrata in °C o in °F"
|
msgstr "scegli se la temperatura deve essere mostrata in °C o in °F"
|
||||||
|
|
||||||
#: curweather.php:197
|
#: curweather.php:191
|
||||||
msgid "Show weather data"
|
msgid "Show weather data"
|
||||||
msgstr "Mostra dati meteo"
|
msgstr "Mostra dati meteo"
|
||||||
|
|
||||||
#: curweather.php:232
|
#: curweather.php:196
|
||||||
|
msgid "Current Weather Settings"
|
||||||
|
msgstr "Impostazioni Meteo"
|
||||||
|
|
||||||
|
#: curweather.php:227
|
||||||
|
msgid "Save Settings"
|
||||||
|
msgstr "Salva Impostazioni"
|
||||||
|
|
||||||
|
#: curweather.php:230
|
||||||
msgid "Caching Interval"
|
msgid "Caching Interval"
|
||||||
msgstr "Intervallo di cache"
|
msgstr "Intervallo di cache"
|
||||||
|
|
||||||
#: curweather.php:234
|
#: curweather.php:232
|
||||||
msgid ""
|
msgid ""
|
||||||
"For how long should the weather data be cached? Choose according your "
|
"For how long should the weather data be cached? Choose according your "
|
||||||
"OpenWeatherMap account type."
|
"OpenWeatherMap account type."
|
||||||
msgstr "Per quanto tempo i dati meteo devono essere memorizzati? Scegli a seconda del tuo tipo di account su OpenWeatherMap."
|
msgstr "Per quanto tempo i dati meteo devono essere memorizzati? Scegli a seconda del tuo tipo di account su OpenWeatherMap."
|
||||||
|
|
||||||
#: curweather.php:235
|
#: curweather.php:233
|
||||||
msgid "no cache"
|
msgid "no cache"
|
||||||
msgstr "nessuna cache"
|
msgstr "nessuna cache"
|
||||||
|
|
||||||
#: curweather.php:236 curweather.php:237 curweather.php:238 curweather.php:239
|
#: curweather.php:234 curweather.php:235 curweather.php:236 curweather.php:237
|
||||||
msgid "minutes"
|
msgid "minutes"
|
||||||
msgstr "minuti"
|
msgstr "minuti"
|
||||||
|
|
||||||
#: curweather.php:242
|
#: curweather.php:240
|
||||||
msgid "Your APPID"
|
msgid "Your APPID"
|
||||||
msgstr "Il tuo APPID"
|
msgstr "Il tuo APPID"
|
||||||
|
|
||||||
#: curweather.php:242
|
#: curweather.php:240
|
||||||
msgid "Your API key provided by OpenWeatherMap"
|
msgid "Your API key provided by OpenWeatherMap"
|
||||||
msgstr "La tua chiave API da OpenWeatherMap"
|
msgstr "La tua chiave API da OpenWeatherMap"
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue