diff --git a/cliupdate.php b/cliupdate.php index f0bf31bfc9..dd82f8fcc2 100644 --- a/cliupdate.php +++ b/cliupdate.php @@ -2,13 +2,14 @@ declare(strict_types=1); +use helpers\UpdateVisitor; +use Psr\Container\ContainerInterface; + chdir(__DIR__); require __DIR__ . '/src/common.php'; -use helpers\UpdateVisitor; - -/** @var Dice\Dice $dice */ -$loader = $dice->create(helpers\ContentLoader::class); +/** @var ContainerInterface $container */ +$loader = $container->get(helpers\ContentLoader::class); $updateVisitor = new class() implements UpdateVisitor { public function started(int $count): void { } diff --git a/composer.json b/composer.json index 479a7942a9..e9a62abbff 100644 --- a/composer.json +++ b/composer.json @@ -14,13 +14,14 @@ "guzzlehttp/psr7": "^2.0", "http-interop/response-sender": "^1.0", "j0k3r/graby": "^2.0", - "level-2/dice": "^4.0", "lordelph/icofileloader": "^2.0", "mibe/feedwriter": "^1.0", "monolog/monolog": "^2.0", "php-http/guzzle7-adapter": "^1.0", + "psr/container": "^1.1", "psr/simple-cache": "^1.0", "simplepie/simplepie": "^1.8", + "slince/di": "^3.2", "smottt/wideimage": "^1.1", "symfony/cache": "^5.4", "symfony/polyfill-php80": "^1.26", diff --git a/composer.lock b/composer.lock index 9aec0bbd3a..35963c1187 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "3d8473e8857fadb3e40111ac659d7270", + "content-hash": "ab1da053d0886465d072851ebc0185d8", "packages": [ { "name": "bcosca/fatfree-core", @@ -158,6 +158,81 @@ ], "time": "2022-02-21T13:15:14+00:00" }, + { + "name": "dflydev/dot-access-data", + "version": "v3.0.2", + "source": { + "type": "git", + "url": "https://github.com/dflydev/dflydev-dot-access-data.git", + "reference": "f41715465d65213d644d3141a6a93081be5d3549" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dflydev/dflydev-dot-access-data/zipball/f41715465d65213d644d3141a6a93081be5d3549", + "reference": "f41715465d65213d644d3141a6a93081be5d3549", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^0.12.42", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.3", + "scrutinizer/ocular": "1.6.0", + "squizlabs/php_codesniffer": "^3.5", + "vimeo/psalm": "^4.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Dflydev\\DotAccessData\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Dragonfly Development Inc.", + "email": "info@dflydev.com", + "homepage": "http://dflydev.com" + }, + { + "name": "Beau Simensen", + "email": "beau@dflydev.com", + "homepage": "http://beausimensen.com" + }, + { + "name": "Carlos Frutos", + "email": "carlos@kiwing.it", + "homepage": "https://github.com/cfrutos" + }, + { + "name": "Colin O'Dell", + "email": "colinodell@gmail.com", + "homepage": "https://www.colinodell.com" + } + ], + "description": "Given a deep data structure, access data by dot notation.", + "homepage": "https://github.com/dflydev/dflydev-dot-access-data", + "keywords": [ + "access", + "data", + "dot", + "notation" + ], + "support": { + "issues": "https://github.com/dflydev/dflydev-dot-access-data/issues", + "source": "https://github.com/dflydev/dflydev-dot-access-data/tree/v3.0.2" + }, + "time": "2022-10-27T11:44:00+00:00" + }, { "name": "fossar/guzzle-transcoder", "version": "0.3.0", @@ -1098,56 +1173,6 @@ ], "time": "2022-06-13T04:15:24+00:00" }, - { - "name": "level-2/dice", - "version": "4.0.4", - "source": { - "type": "git", - "url": "https://github.com/Level-2/Dice.git", - "reference": "e04c98d96bcc932a917b2b7e7944887e4839056a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Level-2/Dice/zipball/e04c98d96bcc932a917b2b7e7944887e4839056a", - "reference": "e04c98d96bcc932a917b2b7e7944887e4839056a", - "shasum": "" - }, - "require": { - "php": ">=7.0.0" - }, - "require-dev": { - "phpunit/phpunit": "^6.5" - }, - "type": "library", - "autoload": { - "psr-4": { - "Dice\\": "./" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-2-Clause" - ], - "authors": [ - { - "name": "Tom Butler", - "email": "tom@r.je" - } - ], - "description": "A minimalist Dependency injection container (DIC) for PHP. Please note: 3.0+ is only compatible with PHP 7.0. The 2.0 branch is compatbile with PHP 5.6.", - "homepage": "http://r.je/dice.html", - "keywords": [ - "dependency injection", - "dependency injection container", - "di", - "ioc" - ], - "support": { - "issues": "https://github.com/Level-2/Dice/issues", - "source": "https://github.com/Level-2/Dice/tree/4.0.4" - }, - "time": "2022-03-28T21:20:23+00:00" - }, { "name": "lordelph/icofileloader", "version": "2.0.1", @@ -2397,6 +2422,59 @@ }, "time": "2023-01-20T08:37:35+00:00" }, + { + "name": "slince/di", + "version": "3.2.2", + "source": { + "type": "git", + "url": "https://github.com/slince/di.git", + "reference": "975d514fadd0edb87a36da7577587f6b75c311a6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/slince/di/zipball/975d514fadd0edb87a36da7577587f6b75c311a6", + "reference": "975d514fadd0edb87a36da7577587f6b75c311a6", + "shasum": "" + }, + "require": { + "dflydev/dot-access-data": "^3.0", + "php": ">=7.4", + "psr/container": "^1.0 || ^2.0" + }, + "require-dev": { + "phpunit/phpunit": "^7.5|^8.0|^9.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Slince\\Di\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Tao", + "email": "taosikai@yeah.net" + } + ], + "description": "A flexible dependency injection container", + "keywords": [ + "PSR-11", + "container", + "dependency injection", + "di", + "injection", + "ioc" + ], + "support": { + "issues": "https://github.com/slince/di/issues", + "source": "https://github.com/slince/di/tree/3.2.2" + }, + "time": "2023-06-15T16:54:45+00:00" + }, { "name": "smalot/pdfparser", "version": "v1.1.0", diff --git a/index.php b/index.php index 735ab92abf..56bb0fa882 100644 --- a/index.php +++ b/index.php @@ -2,166 +2,168 @@ declare(strict_types=1); +use Psr\Container\ContainerInterface; + require __DIR__ . '/src/common.php'; -/** @var Dice\Dice $dice */ -$router = $dice->create(Bramus\Router\Router::class); +/** @var ContainerInterface $container */ +$router = $container->get(Bramus\Router\Router::class); // define routes // all users -$router->get('/', function() use ($dice): void { +$router->get('/', function() use ($container): void { // json - $dice->create(controllers\Index::class)->home(); + $container->get(controllers\Index::class)->home(); }); -$router->get('/api/about', function() use ($dice): void { +$router->get('/api/about', function() use ($container): void { // json - $dice->create(controllers\About::class)->about(); + $container->get(controllers\About::class)->about(); }); -$router->post('/api/private/hash-password', function() use ($dice): void { +$router->post('/api/private/hash-password', function() use ($container): void { // json - $dice->create(controllers\Helpers\HashPassword::class)->hash(); + $container->get(controllers\Helpers\HashPassword::class)->hash(); }); -$router->get('/login', function() use ($dice): void { +$router->get('/login', function() use ($container): void { // json, deprecated - $dice->create(controllers\Authentication::class)->login(); + $container->get(controllers\Authentication::class)->login(); }); -$router->post('/login', function() use ($dice): void { +$router->post('/login', function() use ($container): void { // json - $dice->create(controllers\Authentication::class)->login(); + $container->get(controllers\Authentication::class)->login(); }); -$router->get('/logout', function() use ($dice): void { +$router->get('/logout', function() use ($container): void { // json, deprecated - $dice->create(controllers\Authentication::class)->logout(); + $container->get(controllers\Authentication::class)->logout(); }); -$router->delete('/api/session/current', function() use ($dice): void { +$router->delete('/api/session/current', function() use ($container): void { // json - $dice->create(controllers\Authentication::class)->logout(); + $container->get(controllers\Authentication::class)->logout(); }); -$router->get('/update', function() use ($dice): void { +$router->get('/update', function() use ($container): void { // text - $dice->create(controllers\Sources\Update::class)->updateAll(); + $container->get(controllers\Sources\Update::class)->updateAll(); }); // only for loggedin users or on public mode -$router->get('/rss', function() use ($dice): void { +$router->get('/rss', function() use ($container): void { // rss - $dice->create(controllers\Rss::class)->rss(); + $container->get(controllers\Rss::class)->rss(); }); -$router->get('/feed', function() use ($dice): void { +$router->get('/feed', function() use ($container): void { // rss - $dice->create(controllers\Rss::class)->rss(); + $container->get(controllers\Rss::class)->rss(); }); -$router->get('/items', function() use ($dice): void { +$router->get('/items', function() use ($container): void { // json - $dice->create(controllers\Items::class)->listItems(); + $container->get(controllers\Items::class)->listItems(); }); -$router->get('/tags', function() use ($dice): void { +$router->get('/tags', function() use ($container): void { // json - $dice->create(controllers\Tags::class)->listTags(); + $container->get(controllers\Tags::class)->listTags(); }); -$router->get('/stats', function() use ($dice): void { +$router->get('/stats', function() use ($container): void { // json - $dice->create(controllers\Items\Stats::class)->stats(); + $container->get(controllers\Items\Stats::class)->stats(); }); -$router->get('/items/sync', function() use ($dice): void { +$router->get('/items/sync', function() use ($container): void { // json - $dice->create(controllers\Items\Sync::class)->sync(); + $container->get(controllers\Items\Sync::class)->sync(); }); -$router->get('/sources/stats', function() use ($dice): void { +$router->get('/sources/stats', function() use ($container): void { // json - $dice->create(controllers\Sources::class)->stats(); + $container->get(controllers\Sources::class)->stats(); }); // only loggedin users -$router->post('/mark/([0-9]+)', function(string $itemId) use ($dice): void { +$router->post('/mark/([0-9]+)', function(string $itemId) use ($container): void { // json - $dice->create(controllers\Items::class)->mark($itemId); + $container->get(controllers\Items::class)->mark($itemId); }); -$router->post('/mark', function() use ($dice): void { +$router->post('/mark', function() use ($container): void { // json - $dice->create(controllers\Items::class)->mark(); + $container->get(controllers\Items::class)->mark(); }); -$router->post('/unmark/([0-9]+)', function(string $itemId) use ($dice): void { +$router->post('/unmark/([0-9]+)', function(string $itemId) use ($container): void { // json - $dice->create(controllers\Items::class)->unmark($itemId); + $container->get(controllers\Items::class)->unmark($itemId); }); -$router->post('/starr/([0-9]+)', function(string $itemId) use ($dice): void { +$router->post('/starr/([0-9]+)', function(string $itemId) use ($container): void { // json - $dice->create(controllers\Items::class)->starr($itemId); + $container->get(controllers\Items::class)->starr($itemId); }); -$router->post('/unstarr/([0-9]+)', function(string $itemId) use ($dice): void { +$router->post('/unstarr/([0-9]+)', function(string $itemId) use ($container): void { // json - $dice->create(controllers\Items::class)->unstarr($itemId); + $container->get(controllers\Items::class)->unstarr($itemId); }); -$router->post('/items/sync', function() use ($dice): void { +$router->post('/items/sync', function() use ($container): void { // json - $dice->create(controllers\Items\Sync::class)->updateStatuses(); + $container->get(controllers\Items\Sync::class)->updateStatuses(); }); -$router->get('/source/params', function() use ($dice): void { +$router->get('/source/params', function() use ($container): void { // json - $dice->create(controllers\Sources::class)->params(); + $container->get(controllers\Sources::class)->params(); }); -$router->get('/sources', function() use ($dice): void { +$router->get('/sources', function() use ($container): void { // json - $dice->create(controllers\Sources::class)->show(); + $container->get(controllers\Sources::class)->show(); }); -$router->get('/source', function() use ($dice): void { +$router->get('/source', function() use ($container): void { // json - $dice->create(controllers\Sources::class)->add(); + $container->get(controllers\Sources::class)->add(); }); -$router->get('/sources/list', function() use ($dice): void { +$router->get('/sources/list', function() use ($container): void { // json - $dice->create(controllers\Sources::class)->listSources(); + $container->get(controllers\Sources::class)->listSources(); }); -$router->post('/source/((?:new-)?[0-9]+)', function(string $id) use ($dice): void { +$router->post('/source/((?:new-)?[0-9]+)', function(string $id) use ($container): void { // json - $dice->create(controllers\Sources\Write::class)->write($id); + $container->get(controllers\Sources\Write::class)->write($id); }); -$router->post('/source', function() use ($dice): void { +$router->post('/source', function() use ($container): void { // json - $dice->create(controllers\Sources\Write::class)->write(); + $container->get(controllers\Sources\Write::class)->write(); }); -$router->delete('/source/([0-9]+)', function(string $id) use ($dice): void { +$router->delete('/source/([0-9]+)', function(string $id) use ($container): void { // json - $dice->create(controllers\Sources::class)->remove($id); + $container->get(controllers\Sources::class)->remove($id); }); -$router->post('/source/delete/([0-9]+)', function(string $id) use ($dice): void { +$router->post('/source/delete/([0-9]+)', function(string $id) use ($container): void { // json, deprecated - $dice->create(controllers\Sources::class)->remove($id); + $container->get(controllers\Sources::class)->remove($id); }); -$router->post('/source/([0-9]+)/update', function(string $id) use ($dice): void { +$router->post('/source/([0-9]+)/update', function(string $id) use ($container): void { // json - $dice->create(controllers\Sources\Update::class)->update($id); + $container->get(controllers\Sources\Update::class)->update($id); }); -$router->get('/sources/spouts', function() use ($dice): void { +$router->get('/sources/spouts', function() use ($container): void { // json - $dice->create(controllers\Sources::class)->spouts(); + $container->get(controllers\Sources::class)->spouts(); }); -$router->post('/tags/color', function() use ($dice): void { +$router->post('/tags/color', function() use ($container): void { // json - $dice->create(controllers\Tags::class)->color(); + $container->get(controllers\Tags::class)->color(); }); -$router->get('/opml', function() use ($dice): void { +$router->get('/opml', function() use ($container): void { // html - $dice->create(controllers\Opml\ImportPage::class)->show(); + $container->get(controllers\Opml\ImportPage::class)->show(); }); -$router->post('/opml', function() use ($dice): void { +$router->post('/opml', function() use ($container): void { // json - $dice->create(controllers\Opml\Import::class)->add(); + $container->get(controllers\Opml\Import::class)->add(); }); -$router->get('/opmlexport', function() use ($dice): void { +$router->get('/opmlexport', function() use ($container): void { // xml - $dice->create(controllers\Opml\Export::class)->export(); + $container->get(controllers\Opml\Export::class)->export(); }); // Client side routes need to be directed to index.html. -$router->get('/sign/in|/password|/manage/sources(/add)?|/(newest|unread|starred)(/(all|tag-[^/]+|source-[0-9]+)(/[0-9]+)?)?', function() use ($dice): void { +$router->get('/sign/in|/password|/manage/sources(/add)?|/(newest|unread|starred)(/(all|tag-[^/]+|source-[0-9]+)(/[0-9]+)?)?', function() use ($container): void { // html - $dice->create(controllers\Index::class)->home(); + $container->get(controllers\Index::class)->home(); }); $router->set404(function(): void { diff --git a/phpstan.neon b/phpstan.neon index 32d3d834f9..7341144d01 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -13,7 +13,8 @@ parameters: - vendor/bin/.phpunit/phpunit/vendor/autoload.php stubFiles: - - utils/PHPStan/Stubs/Dice.stub + - utils/PHPStan/Stubs/Container.stub + - utils/PHPStan/Stubs/ContainerInterface.stub - utils/PHPStan/Stubs/IcoFileLoader.stub ignoreErrors: diff --git a/src/common.php b/src/common.php index dcb1ece496..a9e226e320 100644 --- a/src/common.php +++ b/src/common.php @@ -2,7 +2,6 @@ declare(strict_types=1); -use Dice\Dice; use helpers\Configuration; use helpers\DatabaseConnection; use Monolog\Formatter\LineFormatter; @@ -10,7 +9,9 @@ use Monolog\Handler\NullHandler; use Monolog\Handler\StreamHandler; use Monolog\Logger; +use Psr\Container\ContainerInterface; use Psr\SimpleCache\CacheInterface; +use Slince\Di\Container; use Symfony\Component\Cache\Adapter\FilesystemAdapter; use Symfony\Component\Cache\Psr16Cache; @@ -51,39 +52,59 @@ function boot_error(string $message) { $f3->set('DEBUG', $configuration->debug); $f3->set('cache', $configuration->cache); -$dice = new Dice(); - -// DI rules -$substitutions = [ - 'substitutions' => [ - // Instantiate configuration container. - Configuration::class => [ - Dice::INSTANCE => fn() => $configuration, - 'shared' => true, - ], - - Dice::class => [Dice::INSTANCE => Dice::SELF], - ], -]; - -$shared = array_merge($substitutions, [ - 'shared' => true, -]); - -$dice = $dice->addRule(Bramus\Router\Router::class, $shared); -$dice = $dice->addRule(helpers\Authentication::class, $shared); -$dice = $dice->addRule(helpers\Session::class, $shared); +$container = new Container(); +$container->setDefaults(['shared' => false]); + +// Instantiate configuration container. +$container + ->register(Configuration::class, $configuration) + ->setShared(true) +; + +$container + ->register(Bramus\Router\Router::class) + ->setShared(true) +; +$container + ->register(helpers\Authentication::class) + ->setShared(true) +; +$container + ->register(helpers\Session::class) + ->setShared(true) +; // Database bridges -$dice = $dice->addRule(daos\Items::class, $shared); -$dice = $dice->addRule(daos\Sources::class, $shared); -$dice = $dice->addRule(daos\Tags::class, $shared); +$container + ->register(daos\Items::class) + ->setShared(true) +; +$container + ->register(daos\Sources::class) + ->setShared(true) +; +$container + ->register(daos\Tags::class) + ->setShared(true) +; // Choose database implementation based on config -$dice = $dice->addRule(daos\DatabaseInterface::class, array_merge($shared, ['instanceOf' => 'daos\\' . $configuration->dbType . '\\Database'])); -$dice = $dice->addRule(daos\ItemsInterface::class, array_merge($shared, ['instanceOf' => 'daos\\' . $configuration->dbType . '\\Items'])); -$dice = $dice->addRule(daos\SourcesInterface::class, array_merge($shared, ['instanceOf' => 'daos\\' . $configuration->dbType . '\\Sources'])); -$dice = $dice->addRule(daos\TagsInterface::class, array_merge($shared, ['instanceOf' => 'daos\\' . $configuration->dbType . '\\Tags'])); +$container + ->register(daos\DatabaseInterface::class, 'daos\\' . $configuration->dbType . '\\Database') + ->setShared(true) +; +$container + ->register(daos\ItemsInterface::class, 'daos\\' . $configuration->dbType . '\\Items') + ->setShared(true) +; +$container + ->register(daos\SourcesInterface::class, 'daos\\' . $configuration->dbType . '\\Sources') + ->setShared(true) +; +$container + ->register(daos\TagsInterface::class, 'daos\\' . $configuration->dbType . '\\Tags') + ->setShared(true) +; if ($configuration->isChanged('dbSocket') && $configuration->isChanged('dbHost')) { boot_error('You cannot set both `db_socket` and `db_host` options.' . PHP_EOL); @@ -104,7 +125,7 @@ function boot_error(string $message) { // https://www.php.net/manual/en/ref.pdo-sqlite.connection.php $dsn = 'sqlite:' . $db_file; $dbParams = [ - $dsn, + 'dsn' => $dsn, ]; } elseif ($configuration->dbType === 'mysql') { if (!extension_loaded('pdo_mysql')) { @@ -125,11 +146,11 @@ function boot_error(string $message) { } $dbParams = [ - $dsn, - $configuration->dbUsername, - $configuration->dbPassword, - [PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8mb4;'], - $configuration->dbPrefix, + 'dsn' => $dsn, + 'user' => $configuration->dbUsername, + 'password' => $configuration->dbPassword, + 'options' => [PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8mb4;'], + 'tableNamePrefix' => $configuration->dbPrefix, ]; } elseif ($configuration->dbType === 'pgsql') { if (!extension_loaded('pdo_pgsql')) { @@ -148,93 +169,87 @@ function boot_error(string $message) { } $dbParams = [ - $dsn, - $configuration->dbUsername, - $configuration->dbPassword, + 'dsn' => $dsn, + 'user' => $configuration->dbUsername, + 'password' => $configuration->dbPassword, ]; } else { throw new Exception('Unsupported value for db_type option: ' . $configuration->dbType); } -$sqlParams = array_merge($shared, [ - 'constructParams' => $dbParams, -]); +$databaseConnection = + $container + ->register(DatabaseConnection::class) + ->setArguments($dbParams) + ->setShared(true) +; // Define regexp function for SQLite if ($configuration->dbType === 'sqlite') { - $sqlParams = array_merge($sqlParams, [ - 'call' => [ - [ - // https://www.sqlite.org/lang_expr.html#the_like_glob_regexp_match_and_extract_operators - 'sqliteCreateFunction', - [ - 'regexp', - function(string $pattern, string $text): bool { - return preg_match('/' . addcslashes($pattern, '/') . '/', $text) === 1; - }, - 2, - ], - ], - ], - ]); + $databaseConnection->addMethodCall( + // https://www.sqlite.org/lang_expr.html#the_like_glob_regexp_match_and_extract_operators + 'sqliteCreateFunction', + [ + 'regexp', + function(string $pattern, string $text): bool { + return preg_match('/' . addcslashes($pattern, '/') . '/', $text) === 1; + }, + 2, + ] + ); } -$dice = $dice->addRule(DatabaseConnection::class, $sqlParams); - -$dice = $dice->addRule('$iconStorageBackend', [ - 'instanceOf' => helpers\Storage\FileStorage::class, - 'constructParams' => [ - $configuration->datadir . '/favicons', - ], -]); - -$dice = $dice->addRule(helpers\IconStore::class, array_merge($shared, [ - 'constructParams' => [ - [Dice::INSTANCE => '$iconStorageBackend'], - ], -])); - -$dice = $dice->addRule('$thumbnailStorageBackend', [ - 'instanceOf' => helpers\Storage\FileStorage::class, - 'constructParams' => [ - $configuration->datadir . '/thumbnails', - ], -]); - -$dice = $dice->addRule(helpers\ThumbnailStore::class, array_merge($shared, [ - 'constructParams' => [ - [Dice::INSTANCE => '$thumbnailStorageBackend'], - ], -])); - -// Fallback rule -$dice = $dice->addRule('*', $substitutions); - -$dice = $dice->addRule(Logger::class, [ - 'shared' => true, - 'constructParams' => ['selfoss'], -]); - -$dice = $dice->addRule('$fileStorage', array_merge($shared, [ - 'instanceOf' => FilesystemAdapter::class, - 'constructParams' => [ - // namespace - 'selfoss', - // lifetime - 1800, - // directory - $configuration->cache, - ], -])); -$dice = $dice->addRule(CacheInterface::class, array_merge($shared, [ - 'instanceOf' => Psr16Cache::class, - 'constructParams' => [ - [Dice::INSTANCE => '$fileStorage'], - ], -])); +$container + ->register('$iconStorageBackend', helpers\Storage\FileStorage::class) + ->setArgument('directory', $configuration->datadir . '/favicons') +; + +$container + ->register(helpers\IconStore::class) + ->setArgument('storage', new Slince\Di\Reference('$iconStorageBackend')) + ->setShared(true) +; + +$container + ->register('$thumbnailStorageBackend', helpers\Storage\FileStorage::class) + ->setArgument('directory', $configuration->datadir . '/thumbnails') +; + +$container + ->register(helpers\ThumbnailStore::class) + ->setArgument('storage', new Slince\Di\Reference('$thumbnailStorageBackend')) + ->setShared(true) +; + +$container + ->register(Logger::class) + ->setArgument('name', 'selfoss') + ->setShared(true) +; + +$container + ->register('$fileStorage', FilesystemAdapter::class) + ->setArguments([ + 'namespace' => 'selfoss', + 'lifetime' => 1800, + 'directory' => $configuration->cache, + ]) + ->setShared(true) +; + +$container + ->register(CacheInterface::class, Psr16Cache::class) + ->setArgument('pool', new Slince\Di\Reference('$fileStorage')) + ->setShared(true) +; + +$container + ->register(ContainerInterface::class, $container) + ->setShared(true) +; // init logger -$log = $dice->create(Logger::class); +$log = $container->get(Logger::class); if ($configuration->loggerLevel === Configuration::LOGGER_LEVEL_NONE) { $handler = new NullHandler(); diff --git a/src/helpers/DatabaseConnection.php b/src/helpers/DatabaseConnection.php index f2029e2645..d49090b94b 100644 --- a/src/helpers/DatabaseConnection.php +++ b/src/helpers/DatabaseConnection.php @@ -32,13 +32,13 @@ public function __construct( Logger $logger, string $dsn, ?string $user = null, - ?string $pw = null, + ?string $password = null, ?array $options = null, string $tableNamePrefix = '' ) { $this->logger = $logger; $this->logger->debug('Creating database connection', ['dsn' => $dsn]); - $this->pdo = new PDO($dsn, $user, $pw, $options); + $this->pdo = new PDO($dsn, $user, $password, $options); $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $this->tableNamePrefix = $tableNamePrefix; } diff --git a/src/helpers/SpoutLoader.php b/src/helpers/SpoutLoader.php index 59c0a7ae27..490ff4847c 100644 --- a/src/helpers/SpoutLoader.php +++ b/src/helpers/SpoutLoader.php @@ -4,7 +4,7 @@ namespace helpers; -use Dice\Dice; +use Psr\Container\ContainerInterface; use spouts\spout; /** @@ -19,10 +19,10 @@ class SpoutLoader { /** @var ?array>, spout> array of available spouts */ private ?array $spouts = null; - private Dice $dic; + private ContainerInterface $container; - public function __construct(Dice $dice) { - $this->dic = $dice; + public function __construct(ContainerInterface $container) { + $this->container = $container; } /** @@ -51,9 +51,9 @@ public function get(string $spout): ?spout { } try { - $class = $this->dic->create($spout); + $class = $this->container->get($spout); - if (is_subclass_of($class, spout::class)) { + if ($class instanceof spout) { return $class; } else { return null; @@ -108,7 +108,7 @@ protected function loadClasses(string $location, string $parentClassName): array // register widget if (is_subclass_of($className, $parentClassName)) { /** @var P */ - $class = $this->dic->create($className); + $class = $this->container->get($className); $return[$className] = $class; } } diff --git a/tests/Spouts/TwitterTest.php b/tests/Spouts/TwitterTest.php index 73d1fcefea..b78d21f94a 100644 --- a/tests/Spouts/TwitterTest.php +++ b/tests/Spouts/TwitterTest.php @@ -4,7 +4,6 @@ namespace Tests\Spouts; -use Dice\Dice; use GuzzleHttp\Client; use GuzzleHttp\Handler\MockHandler; use GuzzleHttp\HandlerStack; @@ -13,6 +12,7 @@ use helpers\WebClient; use Monolog\Logger; use PHPUnit\Framework\TestCase; +use Slince\Di\Container; use spouts\spout; use spouts\twitter; @@ -36,25 +36,24 @@ private function makeSpout($spout, array $responses): spout { 'handler' => $stack, ]); - $dice = new Dice(); - $dice = $dice->addRule(Logger::class, [ - 'shared' => true, - 'constructParams' => ['selfoss'], - ]); - $dice = $dice->addRule('*', [ - 'substitutions' => [ - WebClient::class => [ - Dice::INSTANCE => function() use ($httpClient) { - $stub = $this->createMock(WebClient::class); - $stub->method('getHttpClient')->willReturn($httpClient); - - return $stub; - }, - ], - ], - ]); + $container = new Container(); + $container->setDefaults(['shared' => false]); + + $container + ->register(Logger::class) + ->setArgument('name', 'selfoss') + ->setShared(true) + ; + $container + ->register(WebClient::class, function() use ($httpClient) { + $stub = $this->createMock(WebClient::class); + $stub->method('getHttpClient')->willReturn($httpClient); + + return $stub; + }) + ; - return $dice->create($spout); + return $container->get($spout); } public function testListTimeline(): void { diff --git a/tests/Spouts/YouTubeTest.php b/tests/Spouts/YouTubeTest.php index ade7df7ccf..146079571a 100644 --- a/tests/Spouts/YouTubeTest.php +++ b/tests/Spouts/YouTubeTest.php @@ -4,7 +4,6 @@ namespace Tests\Spouts; -use Dice\Dice; use Generator; use GuzzleHttp\Client; use GuzzleHttp\Handler\MockHandler; @@ -14,6 +13,7 @@ use helpers\WebClient; use Monolog\Logger; use PHPUnit\Framework\TestCase; +use Slince\Di\Container; use spouts\youtube\youtube; function getResourcePath(string $url): string { @@ -53,25 +53,24 @@ function(array $remoteFile): Response { $stack = HandlerStack::create($mock); $httpClient = new Client(['handler' => $stack]); - $dice = new Dice(); - $dice = $dice->addRule(Logger::class, [ - 'shared' => true, - 'constructParams' => ['selfoss'], - ]); - $dice = $dice->addRule('*', [ - 'substitutions' => [ - WebClient::class => [ - Dice::INSTANCE => function() use ($httpClient) { - $stub = $this->createMock(WebClient::class); - $stub->method('getHttpClient')->willReturn($httpClient); - - return $stub; - }, - ], - ], - ]); + $container = new Container(); + $container->setDefaults(['shared' => false]); + + $container + ->register(Logger::class) + ->setArgument('name', 'selfoss') + ->setShared(true) + ; + $container + ->register(WebClient::class, function() use ($httpClient) { + $stub = $this->createMock(WebClient::class); + $stub->method('getHttpClient')->willReturn($httpClient); + + return $stub; + }) + ; - $yt = $dice->create(youtube::class); + $yt = $container->get(youtube::class); $params = [ 'channel' => $urls[0]['url'], diff --git a/utils/PHPStan/Stubs/Container.stub b/utils/PHPStan/Stubs/Container.stub new file mode 100644 index 0000000000..2742e46391 --- /dev/null +++ b/utils/PHPStan/Stubs/Container.stub @@ -0,0 +1,14 @@ + $id PSR-11 mandates that this is an opaque string but we only use class-strings here. + * + * @phpstan-return T + */ + public function get(string $id); +} diff --git a/utils/PHPStan/Stubs/ContainerInterface.stub b/utils/PHPStan/Stubs/ContainerInterface.stub new file mode 100644 index 0000000000..3f3bb453e5 --- /dev/null +++ b/utils/PHPStan/Stubs/ContainerInterface.stub @@ -0,0 +1,14 @@ + $id PSR-11 mandates that this is an opaque string but we only use class-strings here. + * + * @phpstan-return T + */ + public function get(string $id); +} diff --git a/utils/PHPStan/Stubs/Dice.stub b/utils/PHPStan/Stubs/Dice.stub deleted file mode 100644 index fa6d36e0a9..0000000000 --- a/utils/PHPStan/Stubs/Dice.stub +++ /dev/null @@ -1,15 +0,0 @@ - $name - * @phpstan-param array $args - * - * @phpstan-return T - */ - public function create(string $name, array $args = []); -}