diff --git a/app/modules/api/Controllers/Account/SearchController.php b/app/modules/api/Controllers/Account/SearchController.php index 863727f7..3c446535 100644 --- a/app/modules/api/Controllers/Account/SearchController.php +++ b/app/modules/api/Controllers/Account/SearchController.php @@ -25,16 +25,36 @@ namespace SP\Modules\Api\Controllers\Account; use Exception; +use Klein\Klein; +use SP\Core\Acl\Acl; use SP\Core\Acl\ActionsInterface; -use SP\Domain\Account\Services\AccountSearchFilter; +use SP\Core\Application; +use SP\Domain\Account\AccountSearchServiceInterface; +use SP\Domain\Account\Search\AccountSearchConstants; +use SP\Domain\Account\Search\AccountSearchFilter; +use SP\Domain\Api\ApiServiceInterface; use SP\Domain\Api\Services\ApiResponse; -use SP\Mvc\Model\QueryCondition; +use SP\Modules\Api\Controllers\ControllerBase; /** * Class SearchController */ -final class SearchController extends AccountBase +final class SearchController extends ControllerBase { + private AccountSearchServiceInterface $accountSearchService; + + public function __construct( + Application $application, + Klein $router, + ApiServiceInterface $apiService, + Acl $acl, + AccountSearchServiceInterface $accountSearchService + ) { + parent::__construct($application, $router, $apiService, $acl); + + $this->accountSearchService = $accountSearchService; + } + /** * searchAction */ @@ -46,7 +66,9 @@ final class SearchController extends AccountBase $accountSearchFilter = $this->buildAccountSearchFilter(); $this->returnResponse( - ApiResponse::makeSuccess($this->accountService->getByFilter($accountSearchFilter)->getDataAsArray()) + ApiResponse::makeSuccess( + $this->accountSearchService->getByFilter($accountSearchFilter)->getDataAsArray() + ) ); } catch (Exception $e) { processException($e); @@ -56,40 +78,33 @@ final class SearchController extends AccountBase } /** - * @return \SP\Domain\Account\Services\AccountSearchFilter + * @return \SP\Domain\Account\Search\AccountSearchFilter * @throws \SP\Domain\Common\Services\ServiceException */ private function buildAccountSearchFilter(): AccountSearchFilter { - $accountSearchFilter = new AccountSearchFilter(); - $accountSearchFilter->setCleanTxtSearch($this->apiService->getParamString('text')); - $accountSearchFilter->setCategoryId($this->apiService->getParamInt('categoryId')); - $accountSearchFilter->setClientId($this->apiService->getParamInt('clientId')); + $filter = AccountSearchFilter::build($this->apiService->getParamString('text')) + ->setCategoryId($this->apiService->getParamInt('categoryId')) + ->setClientId($this->apiService->getParamInt('clientId')) + ->setTagsId(array_map('intval', $this->apiService->getParamArray('tagsId', false, []))) + ->setLimitCount($this->apiService->getParamInt('count', false, 50)) + ->setSortOrder( + $this->apiService->getParamInt('order', false, AccountSearchConstants::SORT_DEFAULT) + ); - $tagsId = array_map('intval', $this->apiService->getParamArray('tagsId', false, [])); - - if (count($tagsId) !== 0) { - $accountSearchFilter->setTagsId($tagsId); - } - - $op = $this->apiService->getParamString('op'); + $op = $this->apiService->getParamString('op', false, AccountSearchConstants::FILTER_CHAIN_AND); if ($op !== null) { switch ($op) { - case 'and': - $accountSearchFilter->setFilterOperator(QueryCondition::CONDITION_AND); + case AccountSearchConstants::FILTER_CHAIN_AND: + $filter->setFilterOperator(AccountSearchConstants::FILTER_CHAIN_AND); break; - case 'or': - $accountSearchFilter->setFilterOperator(QueryCondition::CONDITION_OR); + case AccountSearchConstants::FILTER_CHAIN_OR: + $filter->setFilterOperator(AccountSearchConstants::FILTER_CHAIN_OR); break; } } - $accountSearchFilter->setLimitCount($this->apiService->getParamInt('count', false, 50)); - $accountSearchFilter->setSortOrder( - $this->apiService->getParamInt('order', false, AccountSearchFilter::SORT_DEFAULT) - ); - - return $accountSearchFilter; + return $filter; } } \ No newline at end of file diff --git a/app/modules/web/Controllers/AccountManager/SearchController.php b/app/modules/web/Controllers/AccountManager/SearchController.php index 2450c468..d506e2fb 100644 --- a/app/modules/web/Controllers/AccountManager/SearchController.php +++ b/app/modules/web/Controllers/AccountManager/SearchController.php @@ -28,7 +28,7 @@ use SP\Core\Acl\ActionsInterface; use SP\Core\Application; use SP\Domain\Account\AccountSearchServiceInterface; use SP\Domain\Account\AccountServiceInterface; -use SP\Domain\Account\Services\AccountSearchFilter; +use SP\Domain\Account\Search\AccountSearchFilter; use SP\Html\DataGrid\DataGridInterface; use SP\Http\JsonResponse; use SP\Modules\Web\Controllers\ControllerBase; @@ -51,6 +51,10 @@ final class SearchController extends ControllerBase private AccountSearchServiceInterface $accountSearchService; private AccountGrid $accountGrid; + /** + * @throws \SP\Core\Exceptions\SessionTimeout + * @throws \SP\Domain\Auth\Services\AuthException + */ public function __construct( Application $application, WebControllerHelper $webControllerHelper, @@ -67,7 +71,6 @@ final class SearchController extends ControllerBase /** * @return bool - * @throws \JsonException * @throws \SP\Core\Exceptions\ConstraintException * @throws \SP\Core\Exceptions\QueryException * @throws \SP\Core\Exceptions\SPException @@ -100,19 +103,12 @@ final class SearchController extends ControllerBase { $itemSearchData = $this->getSearchData($this->configData->getAccountCount(), $this->request); - $filter = new AccountSearchFilter(); - $filter->setLimitCount($itemSearchData->getLimitCount()); - $filter->setLimitStart($itemSearchData->getLimitStart()); - - if (!empty($itemSearchData->getSeachString())) { - $filter->setStringFilters( - $this->accountSearchService->analyzeQueryFilters($itemSearchData->getSeachString()) - ); - $filter->setCleanTxtSearch($this->accountSearchService->getCleanString()); - } + $filter = AccountSearchFilter::build($itemSearchData->getSeachString()) + ->setLimitCount($itemSearchData->getLimitCount()) + ->setLimitStart($itemSearchData->getLimitStart()); return $this->accountGrid->updatePager( - $this->accountGrid->getGrid($this->accountService->getByFilter($filter)), + $this->accountGrid->getGrid($this->accountSearchService->getByFilter($filter)), $itemSearchData ); } diff --git a/app/modules/web/Controllers/Helpers/Account/AccountSearchHelper.php b/app/modules/web/Controllers/Helpers/Account/AccountSearchHelper.php index 7ac0c859..934e89b9 100644 --- a/app/modules/web/Controllers/Helpers/Account/AccountSearchHelper.php +++ b/app/modules/web/Controllers/Helpers/Account/AccountSearchHelper.php @@ -4,7 +4,7 @@ * * @author nuxsmin * @link https://syspass.org - * @copyright 2012-2021, Rubén Domínguez nuxsmin@$syspass.org + * @copyright 2012-2022, Rubén Domínguez nuxsmin@$syspass.org * * This file is part of sysPass. * @@ -35,7 +35,8 @@ use SP\Core\Exceptions\SPException; use SP\DataModel\ProfileData; use SP\DataModel\UserPreferencesData; use SP\Domain\Account\AccountSearchServiceInterface; -use SP\Domain\Account\Services\AccountSearchFilter; +use SP\Domain\Account\Search\AccountSearchConstants; +use SP\Domain\Account\Search\AccountSearchFilter; use SP\Domain\Account\Services\AccountSearchItem; use SP\Domain\Category\CategoryServiceInterface; use SP\Domain\Client\ClientServiceInterface; @@ -178,7 +179,7 @@ final class AccountSearchHelper extends HelperBase } $dataGrid = $this->getGrid(); - $dataGrid->getData()->setData($this->accountSearchService->processSearchResults($this->accountSearchFilter)); + $dataGrid->getData()->setData($this->accountSearchService->getByFilter($this->accountSearchFilter)); $dataGrid->updatePager(); $dataGrid->setTime(round(getElapsedTime($this->queryTimeStart), 5)); @@ -275,35 +276,35 @@ final class AccountSearchHelper extends HelperBase $gridSortCustomer = new DataGridSort(); $gridSortCustomer->setName(__('Client')) ->setTitle(__('Sort by Client')) - ->setSortKey(AccountSearchFilter::SORT_CLIENT) + ->setSortKey(AccountSearchConstants::SORT_CLIENT) ->setIconUp($icons->getIconUp()) ->setIconDown($icons->getIconDown()); $gridSortName = new DataGridSort(); $gridSortName->setName(__('Name')) ->setTitle(__('Sort by Name')) - ->setSortKey(AccountSearchFilter::SORT_NAME) + ->setSortKey(AccountSearchConstants::SORT_NAME) ->setIconUp($icons->getIconUp()) ->setIconDown($icons->getIconDown()); $gridSortCategory = new DataGridSort(); $gridSortCategory->setName(__('Category')) ->setTitle(__('Sort by Category')) - ->setSortKey(AccountSearchFilter::SORT_CATEGORY) + ->setSortKey(AccountSearchConstants::SORT_CATEGORY) ->setIconUp($icons->getIconUp()) ->setIconDown($icons->getIconDown()); $gridSortLogin = new DataGridSort(); $gridSortLogin->setName(__('User')) ->setTitle(__('Sort by Username')) - ->setSortKey(AccountSearchFilter::SORT_LOGIN) + ->setSortKey(AccountSearchConstants::SORT_LOGIN) ->setIconUp($icons->getIconUp()) ->setIconDown($icons->getIconDown()); $gridSortUrl = new DataGridSort(); $gridSortUrl->setName(__('URL / IP')) ->setTitle(__('Sort by URL / IP')) - ->setSortKey(AccountSearchFilter::SORT_URL) + ->setSortKey(AccountSearchConstants::SORT_URL) ->setIconUp($icons->getIconUp()) ->setIconDown($icons->getIconDown()); @@ -350,7 +351,7 @@ final class AccountSearchHelper extends HelperBase /** * Set search filters * - * @return AccountSearchFilter + * @return \SP\Domain\Account\Search\AccountSearchFilter */ private function getFilters(): AccountSearchFilter { diff --git a/composer.json b/composer.json index daec1c4f..22952958 100644 --- a/composer.json +++ b/composer.json @@ -41,7 +41,8 @@ "league/fractal": "^0.19.2", "symfony/console": "^v5.1.2", "symfony/lock": "^v5.0", - "ocramius/proxy-manager": "~2.0" + "ocramius/proxy-manager": "~2.0", + "aura/sqlquery": "~2.8" }, "require-dev": { "roave/security-advisories": "dev-latest", diff --git a/composer.lock b/composer.lock index d6bedf6c..009c0e09 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": "6fd1ed6990aa4d5a83ef253a9b84f18e", + "content-hash": "8c72e7f9e5d3131fbc6492b91398897c", "packages": [ { "name": "ademarre/binary-to-text-php", @@ -56,6 +56,77 @@ }, "time": "2015-02-27T05:11:22+00:00" }, + { + "name": "aura/sqlquery", + "version": "2.8.0", + "source": { + "type": "git", + "url": "https://github.com/auraphp/Aura.SqlQuery.git", + "reference": "3cadc8bbdeb6cde5fde01349bbd5c4b0fbc1287e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/auraphp/Aura.SqlQuery/zipball/3cadc8bbdeb6cde5fde01349bbd5c4b0fbc1287e", + "reference": "3cadc8bbdeb6cde5fde01349bbd5c4b0fbc1287e", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "yoast/phpunit-polyfills": "~1.0" + }, + "suggest": { + "aura/sql": "Provides an extension to the native PDO along with a profiler and connection locator. Use version 2.*." + }, + "type": "library", + "extra": { + "aura": { + "type": "library" + } + }, + "autoload": { + "psr-4": { + "Aura\\SqlQuery\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Aura.SqlQuery Contributors", + "homepage": "https://github.com/auraphp/Aura.SqlQuery/contributors" + } + ], + "description": "Object-oriented query builders for MySQL, Postgres, SQLite, and SQLServer; can be used with any database connection library.", + "homepage": "https://github.com/auraphp/Aura.SqlQuery", + "keywords": [ + "database", + "db", + "delete", + "dml", + "insert", + "mysql", + "pdo", + "pgsql", + "postgres", + "postgresql", + "query", + "select", + "sql", + "sql server", + "sqlite", + "sqlserver", + "update" + ], + "support": { + "issues": "https://github.com/auraphp/Aura.SqlQuery/issues", + "source": "https://github.com/auraphp/Aura.SqlQuery/tree/2.8.0" + }, + "time": "2022-05-21T13:30:53+00:00" + }, { "name": "defuse/php-encryption", "version": "v2.3.1", @@ -124,16 +195,16 @@ }, { "name": "doctrine/annotations", - "version": "1.13.2", + "version": "1.13.3", "source": { "type": "git", "url": "https://github.com/doctrine/annotations.git", - "reference": "5b668aef16090008790395c02c893b1ba13f7e08" + "reference": "648b0343343565c4a056bfc8392201385e8d89f0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/5b668aef16090008790395c02c893b1ba13f7e08", - "reference": "5b668aef16090008790395c02c893b1ba13f7e08", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/648b0343343565c4a056bfc8392201385e8d89f0", + "reference": "648b0343343565c4a056bfc8392201385e8d89f0", "shasum": "" }, "require": { @@ -145,9 +216,10 @@ "require-dev": { "doctrine/cache": "^1.11 || ^2.0", "doctrine/coding-standard": "^6.0 || ^8.1", - "phpstan/phpstan": "^0.12.20", + "phpstan/phpstan": "^1.4.10 || ^1.8.0", "phpunit/phpunit": "^7.5 || ^8.0 || ^9.1.5", - "symfony/cache": "^4.4 || ^5.2" + "symfony/cache": "^4.4 || ^5.2", + "vimeo/psalm": "^4.10" }, "type": "library", "autoload": { @@ -190,9 +262,9 @@ ], "support": { "issues": "https://github.com/doctrine/annotations/issues", - "source": "https://github.com/doctrine/annotations/tree/1.13.2" + "source": "https://github.com/doctrine/annotations/tree/1.13.3" }, - "time": "2021-08-05T19:00:23+00:00" + "time": "2022-07-02T10:48:51+00:00" }, { "name": "doctrine/cache", @@ -295,26 +367,27 @@ }, { "name": "doctrine/collections", - "version": "1.6.8", + "version": "1.8.0", "source": { "type": "git", "url": "https://github.com/doctrine/collections.git", - "reference": "1958a744696c6bb3bb0d28db2611dc11610e78af" + "reference": "2b44dd4cbca8b5744327de78bafef5945c7e7b5e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/collections/zipball/1958a744696c6bb3bb0d28db2611dc11610e78af", - "reference": "1958a744696c6bb3bb0d28db2611dc11610e78af", + "url": "https://api.github.com/repos/doctrine/collections/zipball/2b44dd4cbca8b5744327de78bafef5945c7e7b5e", + "reference": "2b44dd4cbca8b5744327de78bafef5945c7e7b5e", "shasum": "" }, "require": { + "doctrine/deprecations": "^0.5.3 || ^1", "php": "^7.1.3 || ^8.0" }, "require-dev": { - "doctrine/coding-standard": "^9.0", - "phpstan/phpstan": "^0.12", + "doctrine/coding-standard": "^9.0 || ^10.0", + "phpstan/phpstan": "^1.4.8", "phpunit/phpunit": "^7.5 || ^8.5 || ^9.1.5", - "vimeo/psalm": "^4.2.1" + "vimeo/psalm": "^4.22" }, "type": "library", "autoload": { @@ -358,9 +431,9 @@ ], "support": { "issues": "https://github.com/doctrine/collections/issues", - "source": "https://github.com/doctrine/collections/tree/1.6.8" + "source": "https://github.com/doctrine/collections/tree/1.8.0" }, - "time": "2021-08-10T18:51:53+00:00" + "time": "2022-09-01T20:12:10+00:00" }, { "name": "doctrine/common", @@ -464,38 +537,79 @@ "time": "2020-06-05T16:46:05+00:00" }, { - "name": "doctrine/event-manager", - "version": "1.1.1", + "name": "doctrine/deprecations", + "version": "v1.0.0", "source": { "type": "git", - "url": "https://github.com/doctrine/event-manager.git", - "reference": "41370af6a30faa9dc0368c4a6814d596e81aba7f" + "url": "https://github.com/doctrine/deprecations.git", + "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/event-manager/zipball/41370af6a30faa9dc0368c4a6814d596e81aba7f", - "reference": "41370af6a30faa9dc0368c4a6814d596e81aba7f", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de", + "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de", "shasum": "" }, "require": { + "php": "^7.1|^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^9", + "phpunit/phpunit": "^7.5|^8.5|^9.5", + "psr/log": "^1|^2|^3" + }, + "suggest": { + "psr/log": "Allows logging deprecations via PSR-3 logger implementation" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.", + "homepage": "https://www.doctrine-project.org/", + "support": { + "issues": "https://github.com/doctrine/deprecations/issues", + "source": "https://github.com/doctrine/deprecations/tree/v1.0.0" + }, + "time": "2022-05-02T15:47:09+00:00" + }, + { + "name": "doctrine/event-manager", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/event-manager.git", + "reference": "95aa4cb529f1e96576f3fda9f5705ada4056a520" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/event-manager/zipball/95aa4cb529f1e96576f3fda9f5705ada4056a520", + "reference": "95aa4cb529f1e96576f3fda9f5705ada4056a520", + "shasum": "" + }, + "require": { + "doctrine/deprecations": "^0.5.3 || ^1", "php": "^7.1 || ^8.0" }, "conflict": { - "doctrine/common": "<2.9@dev" + "doctrine/common": "<2.9" }, "require-dev": { - "doctrine/coding-standard": "^6.0", - "phpunit/phpunit": "^7.0" + "doctrine/coding-standard": "^9 || ^10", + "phpstan/phpstan": "~1.4.10 || ^1.8.8", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "vimeo/psalm": "^4.24" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, "autoload": { "psr-4": { - "Doctrine\\Common\\": "lib/Doctrine/Common" + "Doctrine\\Common\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -539,7 +653,7 @@ ], "support": { "issues": "https://github.com/doctrine/event-manager/issues", - "source": "https://github.com/doctrine/event-manager/tree/1.1.x" + "source": "https://github.com/doctrine/event-manager/tree/1.2.0" }, "funding": [ { @@ -555,7 +669,7 @@ "type": "tidelift" } ], - "time": "2020-05-29T18:28:51+00:00" + "time": "2022-10-12T20:51:15+00:00" }, { "name": "doctrine/inflector", @@ -1026,16 +1140,16 @@ }, { "name": "guzzlehttp/promises", - "version": "1.5.1", + "version": "1.5.2", "source": { "type": "git", "url": "https://github.com/guzzle/promises.git", - "reference": "fe752aedc9fd8fcca3fe7ad05d419d32998a06da" + "reference": "b94b2807d85443f9719887892882d0329d1e2598" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/fe752aedc9fd8fcca3fe7ad05d419d32998a06da", - "reference": "fe752aedc9fd8fcca3fe7ad05d419d32998a06da", + "url": "https://api.github.com/repos/guzzle/promises/zipball/b94b2807d85443f9719887892882d0329d1e2598", + "reference": "b94b2807d85443f9719887892882d0329d1e2598", "shasum": "" }, "require": { @@ -1090,7 +1204,7 @@ ], "support": { "issues": "https://github.com/guzzle/promises/issues", - "source": "https://github.com/guzzle/promises/tree/1.5.1" + "source": "https://github.com/guzzle/promises/tree/1.5.2" }, "funding": [ { @@ -1106,7 +1220,7 @@ "type": "tidelift" } ], - "time": "2021-10-22T20:56:57+00:00" + "time": "2022-08-28T14:55:35+00:00" }, { "name": "guzzlehttp/psr7", @@ -1415,16 +1529,16 @@ }, { "name": "laminas/laminas-zendframework-bridge", - "version": "1.5.0", + "version": "1.6.1", "source": { "type": "git", "url": "https://github.com/laminas/laminas-zendframework-bridge.git", - "reference": "7f049390b756d34ba5940a8fb47634fbb51f79ab" + "reference": "e112dd2c099f4f6142c16fc65fda89a638e06885" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-zendframework-bridge/zipball/7f049390b756d34ba5940a8fb47634fbb51f79ab", - "reference": "7f049390b756d34ba5940a8fb47634fbb51f79ab", + "url": "https://api.github.com/repos/laminas/laminas-zendframework-bridge/zipball/e112dd2c099f4f6142c16fc65fda89a638e06885", + "reference": "e112dd2c099f4f6142c16fc65fda89a638e06885", "shasum": "" }, "require": { @@ -1473,29 +1587,30 @@ "type": "community_bridge" } ], - "time": "2022-02-22T22:17:01+00:00" + "time": "2022-07-29T13:28:29+00:00" }, { "name": "laravel/serializable-closure", - "version": "v1.2.0", + "version": "v1.2.2", "source": { "type": "git", "url": "https://github.com/laravel/serializable-closure.git", - "reference": "09f0e9fb61829f628205b7c94906c28740ff9540" + "reference": "47afb7fae28ed29057fdca37e16a84f90cc62fae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/09f0e9fb61829f628205b7c94906c28740ff9540", - "reference": "09f0e9fb61829f628205b7c94906c28740ff9540", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/47afb7fae28ed29057fdca37e16a84f90cc62fae", + "reference": "47afb7fae28ed29057fdca37e16a84f90cc62fae", "shasum": "" }, "require": { "php": "^7.3|^8.0" }, "require-dev": { - "pestphp/pest": "^1.18", - "phpstan/phpstan": "^0.12.98", - "symfony/var-dumper": "^5.3" + "nesbot/carbon": "^2.61", + "pestphp/pest": "^1.21.3", + "phpstan/phpstan": "^1.8.2", + "symfony/var-dumper": "^5.4.11" }, "type": "library", "extra": { @@ -1532,7 +1647,7 @@ "issues": "https://github.com/laravel/serializable-closure/issues", "source": "https://github.com/laravel/serializable-closure" }, - "time": "2022-05-16T17:09:47+00:00" + "time": "2022-09-08T13:45:54+00:00" }, { "name": "league/fractal", @@ -2067,16 +2182,16 @@ }, { "name": "phpmailer/phpmailer", - "version": "v6.6.3", + "version": "v6.6.5", "source": { "type": "git", "url": "https://github.com/PHPMailer/PHPMailer.git", - "reference": "9400f305a898f194caff5521f64e5dfa926626f3" + "reference": "8b6386d7417526d1ea4da9edb70b8352f7543627" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/9400f305a898f194caff5521f64e5dfa926626f3", - "reference": "9400f305a898f194caff5521f64e5dfa926626f3", + "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/8b6386d7417526d1ea4da9edb70b8352f7543627", + "reference": "8b6386d7417526d1ea4da9edb70b8352f7543627", "shasum": "" }, "require": { @@ -2100,8 +2215,8 @@ "hayageek/oauth2-yahoo": "Needed for Yahoo XOAUTH2 authentication", "league/oauth2-google": "Needed for Google XOAUTH2 authentication", "psr/log": "For optional PSR-3 debug logging", - "stevenmaguire/oauth2-microsoft": "Needed for Microsoft XOAUTH2 authentication", - "symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)" + "symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)", + "thenetworg/oauth2-azure": "Needed for Microsoft XOAUTH2 authentication" }, "type": "library", "autoload": { @@ -2133,7 +2248,7 @@ "description": "PHPMailer is a full-featured email creation and transfer class for PHP", "support": { "issues": "https://github.com/PHPMailer/PHPMailer/issues", - "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.6.3" + "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.6.5" }, "funding": [ { @@ -2141,33 +2256,37 @@ "type": "github" } ], - "time": "2022-06-20T09:21:02+00:00" + "time": "2022-10-07T12:23:10+00:00" }, { "name": "phpoption/phpoption", - "version": "1.8.1", + "version": "1.9.0", "source": { "type": "git", "url": "https://github.com/schmittjoh/php-option.git", - "reference": "eab7a0df01fe2344d172bff4cd6dbd3f8b84ad15" + "reference": "dc5ff11e274a90cc1c743f66c9ad700ce50db9ab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/eab7a0df01fe2344d172bff4cd6dbd3f8b84ad15", - "reference": "eab7a0df01fe2344d172bff4cd6dbd3f8b84ad15", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/dc5ff11e274a90cc1c743f66c9ad700ce50db9ab", + "reference": "dc5ff11e274a90cc1c743f66c9ad700ce50db9ab", "shasum": "" }, "require": { - "php": "^7.0 || ^8.0" + "php": "^7.2.5 || ^8.0" }, "require-dev": { - "bamarni/composer-bin-plugin": "^1.4.1", - "phpunit/phpunit": "^6.5.14 || ^7.5.20 || ^8.5.19 || ^9.5.8" + "bamarni/composer-bin-plugin": "^1.8", + "phpunit/phpunit": "^8.5.28 || ^9.5.21" }, "type": "library", "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": true + }, "branch-alias": { - "dev-master": "1.8-dev" + "dev-master": "1.9-dev" } }, "autoload": { @@ -2200,7 +2319,7 @@ ], "support": { "issues": "https://github.com/schmittjoh/php-option/issues", - "source": "https://github.com/schmittjoh/php-option/tree/1.8.1" + "source": "https://github.com/schmittjoh/php-option/tree/1.9.0" }, "funding": [ { @@ -2212,20 +2331,20 @@ "type": "tidelift" } ], - "time": "2021-12-04T23:24:31+00:00" + "time": "2022-07-30T15:51:26+00:00" }, { "name": "phpseclib/phpseclib", - "version": "2.0.37", + "version": "2.0.39", "source": { "type": "git", "url": "https://github.com/phpseclib/phpseclib.git", - "reference": "c812fbb4d6b4d7f30235ab7298a12f09ba13b37c" + "reference": "f3a0e2b715c40cf1fd270d444901b63311725d63" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/c812fbb4d6b4d7f30235ab7298a12f09ba13b37c", - "reference": "c812fbb4d6b4d7f30235ab7298a12f09ba13b37c", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/f3a0e2b715c40cf1fd270d444901b63311725d63", + "reference": "f3a0e2b715c40cf1fd270d444901b63311725d63", "shasum": "" }, "require": { @@ -2240,7 +2359,8 @@ "ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.", "ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.", "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.", - "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations." + "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations.", + "ext-xml": "Install the XML extension to load XML formatted public keys." }, "type": "library", "autoload": { @@ -2305,7 +2425,7 @@ ], "support": { "issues": "https://github.com/phpseclib/phpseclib/issues", - "source": "https://github.com/phpseclib/phpseclib/tree/2.0.37" + "source": "https://github.com/phpseclib/phpseclib/tree/2.0.39" }, "funding": [ { @@ -2321,7 +2441,7 @@ "type": "tidelift" } ], - "time": "2022-04-04T04:57:45+00:00" + "time": "2022-10-24T10:49:03+00:00" }, { "name": "psr/cache", @@ -2569,16 +2689,16 @@ }, { "name": "symfony/console", - "version": "v5.4.9", + "version": "v5.4.15", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "829d5d1bf60b2efeb0887b7436873becc71a45eb" + "reference": "ea59bb0edfaf9f28d18d8791410ee0355f317669" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/829d5d1bf60b2efeb0887b7436873becc71a45eb", - "reference": "829d5d1bf60b2efeb0887b7436873becc71a45eb", + "url": "https://api.github.com/repos/symfony/console/zipball/ea59bb0edfaf9f28d18d8791410ee0355f317669", + "reference": "ea59bb0edfaf9f28d18d8791410ee0355f317669", "shasum": "" }, "require": { @@ -2648,7 +2768,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.4.9" + "source": "https://github.com/symfony/console/tree/v5.4.15" }, "funding": [ { @@ -2664,11 +2784,11 @@ "type": "tidelift" } ], - "time": "2022-05-18T06:17:34+00:00" + "time": "2022-10-26T21:41:52+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v2.5.1", + "version": "v2.5.2", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", @@ -2715,7 +2835,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.1" + "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.2" }, "funding": [ { @@ -2735,16 +2855,16 @@ }, { "name": "symfony/lock", - "version": "v5.4.7", + "version": "v5.4.15", "source": { "type": "git", "url": "https://github.com/symfony/lock.git", - "reference": "a16279554621453840eb8af14d12cfa24c10b8d3" + "reference": "109a20faa6119578b46457ef8cffb9389e20e5ca" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/lock/zipball/a16279554621453840eb8af14d12cfa24c10b8d3", - "reference": "a16279554621453840eb8af14d12cfa24c10b8d3", + "url": "https://api.github.com/repos/symfony/lock/zipball/109a20faa6119578b46457ef8cffb9389e20e5ca", + "reference": "109a20faa6119578b46457ef8cffb9389e20e5ca", "shasum": "" }, "require": { @@ -2794,7 +2914,7 @@ "semaphore" ], "support": { - "source": "https://github.com/symfony/lock/tree/v5.4.7" + "source": "https://github.com/symfony/lock/tree/v5.4.15" }, "funding": [ { @@ -2810,7 +2930,7 @@ "type": "tidelift" } ], - "time": "2022-03-22T15:31:03+00:00" + "time": "2022-10-27T07:55:40+00:00" }, { "name": "symfony/polyfill-ctype", @@ -3469,16 +3589,16 @@ }, { "name": "symfony/service-contracts", - "version": "v2.5.1", + "version": "v2.5.2", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "24d9dc654b83e91aa59f9d167b131bc3b5bea24c" + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/24d9dc654b83e91aa59f9d167b131bc3b5bea24c", - "reference": "24d9dc654b83e91aa59f9d167b131bc3b5bea24c", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c", "shasum": "" }, "require": { @@ -3532,7 +3652,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v2.5.1" + "source": "https://github.com/symfony/service-contracts/tree/v2.5.2" }, "funding": [ { @@ -3548,20 +3668,20 @@ "type": "tidelift" } ], - "time": "2022-03-13T20:07:29+00:00" + "time": "2022-05-30T19:17:29+00:00" }, { "name": "symfony/string", - "version": "v5.4.9", + "version": "v5.4.15", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "985e6a9703ef5ce32ba617c9c7d97873bb7b2a99" + "reference": "571334ce9f687e3e6af72db4d3b2a9431e4fd9ed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/985e6a9703ef5ce32ba617c9c7d97873bb7b2a99", - "reference": "985e6a9703ef5ce32ba617c9c7d97873bb7b2a99", + "url": "https://api.github.com/repos/symfony/string/zipball/571334ce9f687e3e6af72db4d3b2a9431e4fd9ed", + "reference": "571334ce9f687e3e6af72db4d3b2a9431e4fd9ed", "shasum": "" }, "require": { @@ -3618,7 +3738,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v5.4.9" + "source": "https://github.com/symfony/string/tree/v5.4.15" }, "funding": [ { @@ -3634,20 +3754,20 @@ "type": "tidelift" } ], - "time": "2022-04-19T10:40:37+00:00" + "time": "2022-10-05T15:16:54+00:00" }, { "name": "vlucas/phpdotenv", - "version": "v4.2.2", + "version": "v4.3.0", "source": { "type": "git", "url": "https://github.com/vlucas/phpdotenv.git", - "reference": "77e974614d2ead521f18069dccc571696f52b8dc" + "reference": "67a491df68208bef8c37092db11fa3885008efcf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/77e974614d2ead521f18069dccc571696f52b8dc", - "reference": "77e974614d2ead521f18069dccc571696f52b8dc", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/67a491df68208bef8c37092db11fa3885008efcf", + "reference": "67a491df68208bef8c37092db11fa3885008efcf", "shasum": "" }, "require": { @@ -3659,7 +3779,7 @@ "bamarni/composer-bin-plugin": "^1.4.1", "ext-filter": "*", "ext-pcre": "*", - "phpunit/phpunit": "^4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.21" + "phpunit/phpunit": "^4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.30" }, "suggest": { "ext-filter": "Required to use the boolean validator.", @@ -3667,8 +3787,12 @@ }, "type": "library", "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": true + }, "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } }, "autoload": { @@ -3700,7 +3824,7 @@ ], "support": { "issues": "https://github.com/vlucas/phpdotenv/issues", - "source": "https://github.com/vlucas/phpdotenv/tree/v4.2.2" + "source": "https://github.com/vlucas/phpdotenv/tree/v4.3.0" }, "funding": [ { @@ -3712,7 +3836,7 @@ "type": "tidelift" } ], - "time": "2021-12-12T23:07:53+00:00" + "time": "2022-10-16T00:51:09+00:00" }, { "name": "webimpress/safe-writer", @@ -3777,16 +3901,16 @@ "packages-dev": [ { "name": "dg/bypass-finals", - "version": "v1.3.1", + "version": "v1.4.1", "source": { "type": "git", "url": "https://github.com/dg/bypass-finals.git", - "reference": "495f5bc762e7bf30a13ed8253f44bb3a701767bb" + "reference": "4c424c3ed359220fce044f35cdf9f48b0089b2ca" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dg/bypass-finals/zipball/495f5bc762e7bf30a13ed8253f44bb3a701767bb", - "reference": "495f5bc762e7bf30a13ed8253f44bb3a701767bb", + "url": "https://api.github.com/repos/dg/bypass-finals/zipball/4c424c3ed359220fce044f35cdf9f48b0089b2ca", + "reference": "4c424c3ed359220fce044f35cdf9f48b0089b2ca", "shasum": "" }, "require": { @@ -3824,9 +3948,9 @@ ], "support": { "issues": "https://github.com/dg/bypass-finals/issues", - "source": "https://github.com/dg/bypass-finals/tree/v1.3.1" + "source": "https://github.com/dg/bypass-finals/tree/v1.4.1" }, - "time": "2021-04-09T10:42:55+00:00" + "time": "2022-09-13T17:27:26+00:00" }, { "name": "doctrine/instantiator", @@ -4117,16 +4241,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.14.0", + "version": "v4.15.1", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "34bea19b6e03d8153165d8f30bba4c3be86184c1" + "reference": "0ef6c55a3f47f89d7a374e6f835197a0b5fcf900" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/34bea19b6e03d8153165d8f30bba4c3be86184c1", - "reference": "34bea19b6e03d8153165d8f30bba4c3be86184c1", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/0ef6c55a3f47f89d7a374e6f835197a0b5fcf900", + "reference": "0ef6c55a3f47f89d7a374e6f835197a0b5fcf900", "shasum": "" }, "require": { @@ -4167,9 +4291,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.14.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.1" }, - "time": "2022-05-31T20:59:12+00:00" + "time": "2022-09-04T07:30:47+00:00" }, { "name": "phar-io/manifest", @@ -4282,252 +4406,25 @@ }, "time": "2022-02-21T01:04:05+00:00" }, - { - "name": "phpdocumentor/reflection-common", - "version": "2.2.0", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", - "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-2.x": "2.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jaap van Otterdijk", - "email": "opensource@ijaap.nl" - } - ], - "description": "Common reflection classes used by phpdocumentor to reflect the code structure", - "homepage": "http://www.phpdoc.org", - "keywords": [ - "FQSEN", - "phpDocumentor", - "phpdoc", - "reflection", - "static analysis" - ], - "support": { - "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", - "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" - }, - "time": "2020-06-27T09:03:43+00:00" - }, - { - "name": "phpdocumentor/reflection-docblock", - "version": "5.3.0", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "622548b623e81ca6d78b721c5e029f4ce664f170" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/622548b623e81ca6d78b721c5e029f4ce664f170", - "reference": "622548b623e81ca6d78b721c5e029f4ce664f170", - "shasum": "" - }, - "require": { - "ext-filter": "*", - "php": "^7.2 || ^8.0", - "phpdocumentor/reflection-common": "^2.2", - "phpdocumentor/type-resolver": "^1.3", - "webmozart/assert": "^1.9.1" - }, - "require-dev": { - "mockery/mockery": "~1.3.2", - "psalm/phar": "^4.8" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" - }, - { - "name": "Jaap van Otterdijk", - "email": "account@ijaap.nl" - } - ], - "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "support": { - "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", - "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.3.0" - }, - "time": "2021-10-19T17:43:47+00:00" - }, - { - "name": "phpdocumentor/type-resolver", - "version": "1.6.1", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "77a32518733312af16a44300404e945338981de3" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/77a32518733312af16a44300404e945338981de3", - "reference": "77a32518733312af16a44300404e945338981de3", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0", - "phpdocumentor/reflection-common": "^2.0" - }, - "require-dev": { - "ext-tokenizer": "*", - "psalm/phar": "^4.8" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-1.x": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" - } - ], - "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", - "support": { - "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.1" - }, - "time": "2022-03-15T21:29:03+00:00" - }, - { - "name": "phpspec/prophecy", - "version": "v1.15.0", - "source": { - "type": "git", - "url": "https://github.com/phpspec/prophecy.git", - "reference": "bbcd7380b0ebf3961ee21409db7b38bc31d69a13" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/bbcd7380b0ebf3961ee21409db7b38bc31d69a13", - "reference": "bbcd7380b0ebf3961ee21409db7b38bc31d69a13", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.2", - "php": "^7.2 || ~8.0, <8.2", - "phpdocumentor/reflection-docblock": "^5.2", - "sebastian/comparator": "^3.0 || ^4.0", - "sebastian/recursion-context": "^3.0 || ^4.0" - }, - "require-dev": { - "phpspec/phpspec": "^6.0 || ^7.0", - "phpunit/phpunit": "^8.0 || ^9.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Prophecy\\": "src/Prophecy" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com" - }, - { - "name": "Marcello Duarte", - "email": "marcello.duarte@gmail.com" - } - ], - "description": "Highly opinionated mocking framework for PHP 5.3+", - "homepage": "https://github.com/phpspec/prophecy", - "keywords": [ - "Double", - "Dummy", - "fake", - "mock", - "spy", - "stub" - ], - "support": { - "issues": "https://github.com/phpspec/prophecy/issues", - "source": "https://github.com/phpspec/prophecy/tree/v1.15.0" - }, - "time": "2021-12-08T12:19:24+00:00" - }, { "name": "phpunit/php-code-coverage", - "version": "9.2.15", + "version": "9.2.18", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "2e9da11878c4202f97915c1cb4bb1ca318a63f5f" + "reference": "12fddc491826940cf9b7e88ad9664cf51f0f6d0a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/2e9da11878c4202f97915c1cb4bb1ca318a63f5f", - "reference": "2e9da11878c4202f97915c1cb4bb1ca318a63f5f", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/12fddc491826940cf9b7e88ad9664cf51f0f6d0a", + "reference": "12fddc491826940cf9b7e88ad9664cf51f0f6d0a", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.13.0", + "nikic/php-parser": "^4.14", "php": ">=7.3", "phpunit/php-file-iterator": "^3.0.3", "phpunit/php-text-template": "^2.0.2", @@ -4576,7 +4473,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.15" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.18" }, "funding": [ { @@ -4584,7 +4481,7 @@ "type": "github" } ], - "time": "2022-03-07T09:28:20+00:00" + "time": "2022-10-27T13:35:33+00:00" }, { "name": "phpunit/php-file-iterator", @@ -4829,16 +4726,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.5.21", + "version": "9.5.26", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "0e32b76be457de00e83213528f6bb37e2a38fcb1" + "reference": "851867efcbb6a1b992ec515c71cdcf20d895e9d2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/0e32b76be457de00e83213528f6bb37e2a38fcb1", - "reference": "0e32b76be457de00e83213528f6bb37e2a38fcb1", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/851867efcbb6a1b992ec515c71cdcf20d895e9d2", + "reference": "851867efcbb6a1b992ec515c71cdcf20d895e9d2", "shasum": "" }, "require": { @@ -4853,7 +4750,6 @@ "phar-io/manifest": "^2.0.3", "phar-io/version": "^3.0.2", "php": ">=7.3", - "phpspec/prophecy": "^1.12.1", "phpunit/php-code-coverage": "^9.2.13", "phpunit/php-file-iterator": "^3.0.5", "phpunit/php-invoker": "^3.1.1", @@ -4861,19 +4757,16 @@ "phpunit/php-timer": "^5.0.2", "sebastian/cli-parser": "^1.0.1", "sebastian/code-unit": "^1.0.6", - "sebastian/comparator": "^4.0.5", + "sebastian/comparator": "^4.0.8", "sebastian/diff": "^4.0.3", "sebastian/environment": "^5.1.3", - "sebastian/exporter": "^4.0.3", + "sebastian/exporter": "^4.0.5", "sebastian/global-state": "^5.0.1", "sebastian/object-enumerator": "^4.0.3", "sebastian/resource-operations": "^3.0.3", - "sebastian/type": "^3.0", + "sebastian/type": "^3.2", "sebastian/version": "^3.0.2" }, - "require-dev": { - "phpspec/prophecy-phpunit": "^2.0.1" - }, "suggest": { "ext-soap": "*", "ext-xdebug": "*" @@ -4915,7 +4808,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.21" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.26" }, "funding": [ { @@ -4925,9 +4818,13 @@ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" } ], - "time": "2022-06-19T12:14:25+00:00" + "time": "2022-10-28T06:00:21+00:00" }, { "name": "roave/security-advisories", @@ -4935,18 +4832,19 @@ "source": { "type": "git", "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "880f953435f266cf634bb81fa8888e66fa7814f6" + "reference": "3adb9cc9ab821d31bcb426ee3cad4c865899349a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/880f953435f266cf634bb81fa8888e66fa7814f6", - "reference": "880f953435f266cf634bb81fa8888e66fa7814f6", + "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/3adb9cc9ab821d31bcb426ee3cad4c865899349a", + "reference": "3adb9cc9ab821d31bcb426ee3cad4c865899349a", "shasum": "" }, "conflict": { "3f/pygmentize": "<1.2", "admidio/admidio": "<4.1.9", "adodb/adodb-php": "<=5.20.20|>=5.21,<=5.21.3", + "aheinze/cockpit": "<=2.2.1", "akaunting/akaunting": "<2.1.13", "alextselegidis/easyappointments": "<=1.4.3", "alterphp/easyadmin-extension-bundle": ">=1.2,<1.2.11|>=1.3,<1.3.1", @@ -4960,7 +4858,9 @@ "appwrite/server-ce": "<0.11.1|>=0.12,<0.12.2", "area17/twill": "<1.2.5|>=2,<2.5.3", "asymmetricrypt/asymmetricrypt": ">=0,<9.9.99", + "awesome-support/awesome-support": "<=6.0.7", "aws/aws-sdk-php": ">=3,<3.2.1", + "badaso/core": "<2.6.1", "bagisto/bagisto": "<0.1.5", "barrelstrength/sprout-base-email": "<1.2.7", "barrelstrength/sprout-forms": "<3.9", @@ -4985,24 +4885,25 @@ "cart2quote/module-quotation": ">=4.1.6,<=4.4.5|>=5,<5.4.4", "cartalyst/sentry": "<=2.1.6", "catfan/medoo": "<1.7.5", - "centreon/centreon": "<20.10.7", + "centreon/centreon": "<21.4.16|>=21.10,<21.10.8|>=22,<22.4.1", "cesnet/simplesamlphp-module-proxystatistics": "<3.1", "codeception/codeception": "<3.1.3|>=4,<4.1.22", "codeigniter/framework": "<=3.0.6", - "codeigniter4/framework": "<4.1.9", + "codeigniter4/framework": "<4.2.7", + "codeigniter4/shield": "= 1.0.0-beta", "codiad/codiad": "<=2.8.4", "composer/composer": "<1.10.26|>=2-alpha.1,<2.2.12|>=2.3,<2.3.5", "concrete5/concrete5": "<9", - "concrete5/core": "<8.5.7", + "concrete5/core": "<8.5.8|>=9,<9.1", "contao-components/mediaelement": ">=2.14.2,<2.21.1", "contao/contao": ">=4,<4.4.56|>=4.5,<4.9.18|>=4.10,<4.11.7|>=4.13,<4.13.3", "contao/core": ">=2,<3.5.39", "contao/core-bundle": "<4.9.18|>=4.10,<4.11.7|>=4.13,<4.13.3|= 4.10.0", "contao/listing-bundle": ">=4,<4.4.8", "contao/managed-edition": "<=1.5", - "craftcms/cms": "<3.7.36", + "craftcms/cms": "<3.7.55.2|>= 4.0.0-RC1, < 4.2.1", "croogo/croogo": "<3.0.7", - "cuyz/valinor": ">=0.5,<0.7", + "cuyz/valinor": "<0.12", "czproject/git-php": "<4.0.3", "darylldoyle/safe-svg": "<1.9.10", "datadog/dd-trace": ">=0.30,<0.30.2", @@ -5019,17 +4920,20 @@ "doctrine/mongodb-odm-bundle": ">=2,<3.0.1", "doctrine/orm": ">=2,<2.4.8|>=2.5,<2.5.1|>=2.8.3,<2.8.4", "dolibarr/dolibarr": "<16|= 12.0.5|>= 3.3.beta1, < 13.0.2", - "dompdf/dompdf": "<1.2.1", - "drupal/core": ">=7,<7.88|>=8,<9.2.13|>=9.3,<9.3.6", + "dompdf/dompdf": "<2.0.1", + "drupal/core": ">=7,<7.91|>=8,<9.3.19|>=9.4,<9.4.3", "drupal/drupal": ">=7,<7.80|>=8,<8.9.16|>=9,<9.1.12|>=9.2,<9.2.4", "dweeves/magmi": "<=0.7.24", "ecodev/newsletter": "<=4", "ectouch/ectouch": "<=2.7.2", + "elefant/cms": "<1.3.13", "elgg/elgg": "<3.3.24|>=4,<4.0.5", "endroid/qr-code-bundle": "<3.4.2", "enshrined/svg-sanitize": "<0.15", "erusev/parsedown": "<1.7.2", "ether/logs": "<3.0.4", + "exceedone/exment": "<4.4.3|>=5,<5.0.3", + "exceedone/laravel-admin": "= 3.0.0|<2.2.3", "ezsystems/demobundle": ">=5.4,<5.4.6.1", "ezsystems/ez-support-tools": ">=2.2,<2.2.3", "ezsystems/ezdemo-ls-extension": ">=5.4,<5.4.2.1", @@ -5049,7 +4953,7 @@ "facade/ignition": "<1.16.15|>=2,<2.4.2|>=2.5,<2.5.2", "facturascripts/facturascripts": "<=2022.8", "feehi/cms": "<=2.1.1", - "feehi/feehicms": "<=0.1.3", + "feehi/feehicms": "<=2.0.1.1", "fenom/fenom": "<=2.12.1", "filegator/filegator": "<7.8", "firebase/php-jwt": "<2", @@ -5057,23 +4961,25 @@ "flarum/sticky": ">=0.1-beta.14,<=0.1-beta.15", "flarum/tags": "<=0.1-beta.13", "fluidtypo3/vhs": "<5.1.1", + "fof/byobu": ">=0.3-beta.2,<1.1.7", "fof/upload": "<1.2.3", "fooman/tcpdf": "<6.2.22", "forkcms/forkcms": "<5.11.1", "fossar/tcpdf-parser": "<6.2.22", - "francoisjacquet/rosariosis": "<9.1", + "francoisjacquet/rosariosis": "<10.1", "friendsofsymfony/oauth2-php": "<1.3", "friendsofsymfony/rest-bundle": ">=1.2,<1.2.2", "friendsofsymfony/user-bundle": ">=1.2,<1.3.5", "friendsoftypo3/mediace": ">=7.6.2,<7.6.5", "froala/wysiwyg-editor": "<3.2.7", - "froxlor/froxlor": "<=0.10.22", + "froxlor/froxlor": "<0.10.38", "fuel/core": "<1.8.1", "gaoming13/wechat-php-sdk": "<=1.10.2", "genix/cms": "<=1.1.11", - "getgrav/grav": "<1.7.33", - "getkirby/cms": "<3.5.8", + "getgrav/grav": "<1.7.34", + "getkirby/cms": "= 3.8.0|<3.5.8.2|>=3.6,<3.6.6.2|>=3.7,<3.7.5.1", "getkirby/panel": "<2.5.14", + "getkirby/starterkit": "<=3.7.0.2", "gilacms/gila": "<=1.11.4", "globalpayments/php-sdk": "<2", "google/protobuf": "<3.15", @@ -5091,6 +4997,7 @@ "ibexa/core": ">=4,<4.0.7|>=4.1,<4.1.4", "ibexa/post-install": "<=1.0.4", "icecoder/icecoder": "<=8.1", + "idno/known": "<=1.3.1", "illuminate/auth": ">=4,<4.0.99|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.10", "illuminate/cookie": ">=4,<=4.0.11|>=4.1,<=4.1.99999|>=4.2,<=4.2.99999|>=5,<=5.0.99999|>=5.1,<=5.1.99999|>=5.2,<=5.2.99999|>=5.3,<=5.3.99999|>=5.4,<=5.4.99999|>=5.5,<=5.5.49|>=5.6,<=5.6.99999|>=5.7,<=5.7.99999|>=5.8,<=5.8.99999|>=6,<6.18.31|>=7,<7.22.4", "illuminate/database": "<6.20.26|>=7,<7.30.5|>=8,<8.40", @@ -5098,7 +5005,9 @@ "illuminate/view": "<6.20.42|>=7,<7.30.6|>=8,<8.75", "impresscms/impresscms": "<=1.4.3", "in2code/femanager": "<5.5.1|>=6,<6.3.1", + "in2code/lux": "<17.6.1|>=18,<24.0.2", "intelliants/subrion": "<=4.2.1", + "islandora/islandora": ">=2,<2.4.1", "ivankristianto/phpwhois": "<=4.3", "jackalope/jackalope-doctrine-dbal": "<1.7.4", "james-heinrich/getid3": "<1.9.21", @@ -5107,6 +5016,7 @@ "joomla/filter": "<1.4.4|>=2,<2.0.1", "joomla/input": ">=2,<2.0.2", "joomla/session": "<1.3.1", + "joyqi/hyper-down": "<=2.4.27", "jsdecena/laracom": "<2.0.9", "jsmitty12/phpwhois": "<5.1", "kazist/phpwhois": "<=4.2.6", @@ -5116,11 +5026,11 @@ "krayin/laravel-crm": "<1.2.2", "kreait/firebase-php": ">=3.2,<3.8.1", "la-haute-societe/tcpdf": "<6.2.22", + "laminas/laminas-diactoros": "<2.11.1", "laminas/laminas-form": "<2.17.1|>=3,<3.0.2|>=3.1,<3.1.1", "laminas/laminas-http": "<2.14.2", "laravel/fortify": "<1.11.1", "laravel/framework": "<6.20.42|>=7,<7.30.6|>=8,<8.75", - "laravel/laravel": "<=9.1.8", "laravel/socialite": ">=1,<1.0.99|>=2,<2.0.10", "latte/latte": "<2.10.8", "lavalite/cms": "<=5.8", @@ -5128,7 +5038,7 @@ "league/commonmark": "<0.18.3", "league/flysystem": "<1.1.4|>=2,<2.1.1", "lexik/jwt-authentication-bundle": "<2.10.7|>=2.11,<2.11.3", - "librenms/librenms": "<22.4", + "librenms/librenms": "<=22.8", "limesurvey/limesurvey": "<3.27.19", "livehelperchat/livehelperchat": "<=3.91", "livewire/livewire": ">2.2.4,<2.2.6", @@ -5143,7 +5053,11 @@ "matyhtf/framework": "<3.0.6", "mautic/core": "<4.3|= 2.13.1", "mediawiki/core": ">=1.27,<1.27.6|>=1.29,<1.29.3|>=1.30,<1.30.2|>=1.31,<1.31.9|>=1.32,<1.32.6|>=1.32.99,<1.33.3|>=1.33.99,<1.34.3|>=1.34.99,<1.35", - "microweber/microweber": "<1.3", + "melisplatform/melis-asset-manager": "<5.0.1", + "melisplatform/melis-cms": "<5.0.1", + "melisplatform/melis-front": "<5.0.1", + "mezzio/mezzio-swoole": "<3.7|>=4,<4.3", + "microweber/microweber": "<=1.3.1", "miniorange/miniorange-saml": "<1.4.3", "mittwald/typo3_forum": "<1.2.1", "modx/revolution": "<= 2.8.3-pl|<2.8", @@ -5162,6 +5076,7 @@ "nette/application": ">=2,<2.0.19|>=2.1,<2.1.13|>=2.2,<2.2.10|>=2.3,<2.3.14|>=2.4,<2.4.16|>=3,<3.0.6", "nette/nette": ">=2,<2.0.19|>=2.1,<2.1.13", "nilsteampassnet/teampass": "<=2.1.27.36", + "notrinos/notrinos-erp": "<=0.7", "noumo/easyii": "<=0.9", "nukeviet/nukeviet": "<4.5.2", "nystudio107/craft-seomatic": "<3.4.12", @@ -5170,7 +5085,7 @@ "october/cms": "= 1.1.1|= 1.0.471|= 1.0.469|>=1.0.319,<1.0.469", "october/october": ">=1.0.319,<1.0.466|>=2.1,<2.1.12", "october/rain": "<1.0.472|>=1.1,<1.1.2", - "october/system": "<1.0.475|>=1.1,<1.1.11|>=2,<2.1.27", + "october/system": "<1.0.476|>=1.1,<1.1.12|>=2,<2.2.34|>=3,<3.0.66", "onelogin/php-saml": "<2.10.4", "oneup/uploader-bundle": "<1.9.3|>=2,<2.1.5", "open-web-analytics/open-web-analytics": "<1.7.4", @@ -5178,8 +5093,10 @@ "openid/php-openid": "<2.3", "openmage/magento-lts": "<19.4.15|>=20,<20.0.13", "orchid/platform": ">=9,<9.4.4", + "oro/commerce": ">=4.1,<5.0.6", "oro/crm": ">=1.7,<1.7.4|>=3.1,<4.1.17|>=4.2,<4.2.7", "oro/platform": ">=1.7,<1.7.4|>=3.1,<3.1.29|>=4.1,<4.1.17|>=4.2,<4.2.8", + "packbackbooks/lti-1-3-php-library": "<5", "padraic/humbug_get_contents": "<1.1.2", "pagarme/pagarme-php": ">=0,<3", "pagekit/pagekit": "<=1.0.18", @@ -5195,6 +5112,7 @@ "phpmailer/phpmailer": "<6.5", "phpmussel/phpmussel": ">=1,<1.6", "phpmyadmin/phpmyadmin": "<5.1.3", + "phpmyfaq/phpmyfaq": "<=3.1.7", "phpoffice/phpexcel": "<1.8", "phpoffice/phpspreadsheet": "<1.16", "phpseclib/phpseclib": "<2.0.31|>=3,<3.0.7", @@ -5203,16 +5121,16 @@ "phpwhois/phpwhois": "<=4.2.5", "phpxmlrpc/extras": "<0.6.1", "pimcore/data-hub": "<1.2.4", - "pimcore/pimcore": "<10.4.4", + "pimcore/pimcore": "<10.5.9", "pocketmine/bedrock-protocol": "<8.0.2", - "pocketmine/pocketmine-mp": ">= 4.0.0-BETA5, < 4.4.2|<4.2.10", + "pocketmine/pocketmine-mp": "<4.7.2|>= 4.0.0-BETA5, < 4.4.2", "pressbooks/pressbooks": "<5.18", "prestashop/autoupgrade": ">=4,<4.10.1", "prestashop/blockwishlist": ">=2,<2.1.1", - "prestashop/contactform": ">1.0.1,<4.3", + "prestashop/contactform": ">=1.0.1,<4.3", "prestashop/gamification": "<2.3.2", - "prestashop/prestashop": ">=1.7,<=1.7.8.2", - "prestashop/productcomments": ">=4,<4.2.1", + "prestashop/prestashop": ">=1.6.0.10,<1.7.8.7", + "prestashop/productcomments": "<5.0.2", "prestashop/ps_emailsubscription": "<2.6.1", "prestashop/ps_facetedsearch": "<3.4.1", "prestashop/ps_linklist": "<3.1", @@ -5224,6 +5142,8 @@ "pusher/pusher-php-server": "<2.2.1", "pwweb/laravel-core": "<=0.3.6-beta", "rainlab/debugbar-plugin": "<3.1", + "rankmath/seo-by-rank-math": "<=1.0.95", + "react/http": ">=0.7,<1.7", "remdex/livehelperchat": "<3.99", "rmccue/requests": ">=1.6,<1.8", "robrichards/xmlseclibs": "<3.0.4", @@ -5238,17 +5158,18 @@ "shopware/core": "<=6.4.9", "shopware/platform": "<=6.4.9", "shopware/production": "<=6.3.5.2", - "shopware/shopware": "<5.7.12", + "shopware/shopware": "<=5.7.14", "shopware/storefront": "<=6.4.8.1", "shopxo/shopxo": "<2.2.6", "showdoc/showdoc": "<2.10.4", "silverstripe/admin": ">=1,<1.8.1", - "silverstripe/assets": ">=1,<1.4.7|>=1.5,<1.5.2", + "silverstripe/assets": ">=1,<1.10.1", "silverstripe/cms": "<4.3.6|>=4.4,<4.4.4", "silverstripe/comments": ">=1.3,<1.9.99|>=2,<2.9.99|>=3,<3.1.1", "silverstripe/forum": "<=0.6.1|>=0.7,<=0.7.3", - "silverstripe/framework": "<4.10.1", + "silverstripe/framework": "<4.10.9", "silverstripe/graphql": "<3.5.2|>=4-alpha.1,<4-alpha.2|= 4.0.0-alpha1", + "silverstripe/hybridsessions": ">=1,<2.4.1|>=2.5,<2.5.1", "silverstripe/registry": ">=2.1,<2.1.2|>=2.2,<2.2.1", "silverstripe/restfulserver": ">=1,<1.0.9|>=2,<2.0.4", "silverstripe/silverstripe-omnipay": "<2.5.2|>=3,<3.0.2|>=3.1,<3.1.4|>=3.2,<3.2.1", @@ -5261,8 +5182,8 @@ "simplesamlphp/simplesamlphp-module-infocard": "<1.0.1", "simplito/elliptic-php": "<1.0.6", "slim/slim": "<2.6", - "smarty/smarty": "<3.1.45|>=4,<4.1.1", - "snipe/snipe-it": "<5.4.4|>= 6.0.0-RC-1, <= 6.0.0-RC-5", + "smarty/smarty": "<3.1.47|>=4,<4.2.1", + "snipe/snipe-it": "<6.0.11|>= 6.0.0-RC-1, <= 6.0.0-RC-5", "socalnick/scn-social-auth": "<1.15.2", "socialiteproviders/steam": "<1.1", "spipu/html2pdf": "<5.2.4", @@ -5321,25 +5242,28 @@ "thelia/backoffice-default-template": ">=2.1,<2.1.2", "thelia/thelia": ">=2.1-beta.1,<2.1.3", "theonedemon/phpwhois": "<=4.2.5", + "thinkcmf/thinkcmf": "<=5.1.7", + "thorsten/phpmyfaq": "<=3.1.7", "tinymce/tinymce": "<5.10", "titon/framework": ">=0,<9.9.99", - "topthink/framework": "<6.0.12", + "topthink/framework": "<=6.0.13", "topthink/think": "<=6.0.9", "topthink/thinkphp": "<=3.2.3", "tribalsystems/zenario": "<9.2.55826", "truckersmp/phpwhois": "<=4.3.1", - "twig/twig": "<1.38|>=2,<2.14.11|>=3,<3.3.8", - "typo3/cms": ">=6.2,<6.2.30|>=7,<7.6.32|>=8,<8.7.38|>=9,<9.5.29|>=10,<10.4.29|>=11,<11.5.11", + "twig/twig": "<1.44.7|>=2,<2.15.3|>=3,<3.4.3", + "typo3/cms": ">=6.2,<6.2.30|>=7,<7.6.32|>=8,<8.7.38|>=9,<9.5.29|>=10,<10.4.32|>=11,<11.5.16", "typo3/cms-backend": ">=7,<=7.6.50|>=8,<=8.7.39|>=9,<=9.5.24|>=10,<=10.4.13|>=11,<=11.1", - "typo3/cms-core": ">=6.2,<=6.2.56|>=7,<7.6.57|>=8,<8.7.47|>=9,<9.5.35|>=10,<10.4.29|>=11,<11.5.11", + "typo3/cms-core": ">=6.2,<=6.2.56|>=7,<7.6.58|>=8,<8.7.48|>=9,<9.5.37|>=10,<10.4.32|>=11,<11.5.16", "typo3/cms-form": ">=8,<=8.7.39|>=9,<=9.5.24|>=10,<=10.4.13|>=11,<=11.1", "typo3/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.12|>=3.1,<3.1.10|>=3.2,<3.2.13|>=3.3,<3.3.13|>=4,<4.0.6", + "typo3/html-sanitizer": ">=1,<1.0.7|>=2,<2.0.16", "typo3/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4|>=2.3,<2.3.99|>=3,<3.0.20|>=3.1,<3.1.18|>=3.2,<3.2.14|>=3.3,<3.3.23|>=4,<4.0.17|>=4.1,<4.1.16|>=4.2,<4.2.12|>=4.3,<4.3.3", "typo3/phar-stream-wrapper": ">=1,<2.1.1|>=3,<3.1.1", "typo3/swiftmailer": ">=4.1,<4.1.99|>=5.4,<5.4.5", "typo3fluid/fluid": ">=2,<2.0.8|>=2.1,<2.1.7|>=2.2,<2.2.4|>=2.3,<2.3.7|>=2.4,<2.4.4|>=2.5,<2.5.11|>=2.6,<2.6.10", "ua-parser/uap-php": "<3.8", - "unisharp/laravel-filemanager": "<=2.3", + "unisharp/laravel-filemanager": "<=2.5.1", "userfrosting/userfrosting": ">=0.3.1,<4.6.3", "usmanhalalit/pixie": "<1.0.3|>=2,<2.0.2", "vanilla/safecurl": "<0.9.2", @@ -5351,12 +5275,14 @@ "webcoast/deferred-image-processing": "<1.0.2", "wikimedia/parsoid": "<0.12.2", "willdurand/js-translation-bundle": "<2.1.1", + "wintercms/winter": "<1.0.475|>=1.1,<1.1.10|>=1.2,<1.2.1", + "woocommerce/woocommerce": "<6.6", "wp-cli/wp-cli": "<2.5", "wp-graphql/wp-graphql": "<0.3.5", "wpanel/wpanel4-cms": "<=4.3.1", "wwbn/avideo": "<=11.6", "yeswiki/yeswiki": "<4.1", - "yetiforce/yetiforce-crm": "<6.4", + "yetiforce/yetiforce-crm": "<=6.4", "yidashi/yii2cmf": "<=2", "yii2mod/yii2-cms": "<1.9.2", "yiisoft/yii": ">=1.1.14,<1.1.15", @@ -5430,7 +5356,7 @@ "type": "tidelift" } ], - "time": "2022-06-25T08:04:47+00:00" + "time": "2022-10-29T01:33:46+00:00" }, { "name": "sebastian/cli-parser", @@ -5601,16 +5527,16 @@ }, { "name": "sebastian/comparator", - "version": "4.0.6", + "version": "4.0.8", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "55f4261989e546dc112258c7a75935a81a7ce382" + "reference": "fa0f136dd2334583309d32b62544682ee972b51a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/55f4261989e546dc112258c7a75935a81a7ce382", - "reference": "55f4261989e546dc112258c7a75935a81a7ce382", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a", + "reference": "fa0f136dd2334583309d32b62544682ee972b51a", "shasum": "" }, "require": { @@ -5663,7 +5589,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", - "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.6" + "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8" }, "funding": [ { @@ -5671,7 +5597,7 @@ "type": "github" } ], - "time": "2020-10-26T15:49:45+00:00" + "time": "2022-09-14T12:41:17+00:00" }, { "name": "sebastian/complexity", @@ -5861,16 +5787,16 @@ }, { "name": "sebastian/exporter", - "version": "4.0.4", + "version": "4.0.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "65e8b7db476c5dd267e65eea9cab77584d3cfff9" + "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/65e8b7db476c5dd267e65eea9cab77584d3cfff9", - "reference": "65e8b7db476c5dd267e65eea9cab77584d3cfff9", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", + "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", "shasum": "" }, "require": { @@ -5926,7 +5852,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/exporter/issues", - "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.4" + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.5" }, "funding": [ { @@ -5934,7 +5860,7 @@ "type": "github" } ], - "time": "2021-11-11T14:18:36+00:00" + "time": "2022-09-14T06:03:37+00:00" }, { "name": "sebastian/global-state", @@ -6289,16 +6215,16 @@ }, { "name": "sebastian/type", - "version": "3.0.0", + "version": "3.2.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/type.git", - "reference": "b233b84bc4465aff7b57cf1c4bc75c86d00d6dad" + "reference": "fb3fe09c5f0bae6bc27ef3ce933a1e0ed9464b6e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/b233b84bc4465aff7b57cf1c4bc75c86d00d6dad", - "reference": "b233b84bc4465aff7b57cf1c4bc75c86d00d6dad", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/fb3fe09c5f0bae6bc27ef3ce933a1e0ed9464b6e", + "reference": "fb3fe09c5f0bae6bc27ef3ce933a1e0ed9464b6e", "shasum": "" }, "require": { @@ -6310,7 +6236,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "3.2-dev" } }, "autoload": { @@ -6333,7 +6259,7 @@ "homepage": "https://github.com/sebastianbergmann/type", "support": { "issues": "https://github.com/sebastianbergmann/type/issues", - "source": "https://github.com/sebastianbergmann/type/tree/3.0.0" + "source": "https://github.com/sebastianbergmann/type/tree/3.2.0" }, "funding": [ { @@ -6341,7 +6267,7 @@ "type": "github" } ], - "time": "2022-03-15T09:54:48+00:00" + "time": "2022-09-12T14:47:03+00:00" }, { "name": "sebastian/version", @@ -6398,16 +6324,16 @@ }, { "name": "symfony/browser-kit", - "version": "v5.4.3", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/browser-kit.git", - "reference": "18e73179c6a33d520de1b644941eba108dd811ad" + "reference": "081fe28a26b6bd671dea85ef3a4b5003f3c88027" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/browser-kit/zipball/18e73179c6a33d520de1b644941eba108dd811ad", - "reference": "18e73179c6a33d520de1b644941eba108dd811ad", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/081fe28a26b6bd671dea85ef3a4b5003f3c88027", + "reference": "081fe28a26b6bd671dea85ef3a4b5003f3c88027", "shasum": "" }, "require": { @@ -6450,7 +6376,7 @@ "description": "Simulates the behavior of a web browser, allowing you to make requests, click on links and submit forms programmatically", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/browser-kit/tree/v5.4.3" + "source": "https://github.com/symfony/browser-kit/tree/v5.4.11" }, "funding": [ { @@ -6466,20 +6392,20 @@ "type": "tidelift" } ], - "time": "2022-01-02T09:53:40+00:00" + "time": "2022-07-27T15:50:05+00:00" }, { "name": "symfony/css-selector", - "version": "v5.4.3", + "version": "v5.4.11", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "b0a190285cd95cb019237851205b8140ef6e368e" + "reference": "c1681789f059ab756001052164726ae88512ae3d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/b0a190285cd95cb019237851205b8140ef6e368e", - "reference": "b0a190285cd95cb019237851205b8140ef6e368e", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/c1681789f059ab756001052164726ae88512ae3d", + "reference": "c1681789f059ab756001052164726ae88512ae3d", "shasum": "" }, "require": { @@ -6516,7 +6442,7 @@ "description": "Converts CSS selectors to XPath expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/css-selector/tree/v5.4.3" + "source": "https://github.com/symfony/css-selector/tree/v5.4.11" }, "funding": [ { @@ -6532,7 +6458,7 @@ "type": "tidelift" } ], - "time": "2022-01-02T09:53:40+00:00" + "time": "2022-06-27T16:58:25+00:00" }, { "name": "symfony/debug", @@ -6605,16 +6531,16 @@ }, { "name": "symfony/dom-crawler", - "version": "v5.4.9", + "version": "v5.4.15", "source": { "type": "git", "url": "https://github.com/symfony/dom-crawler.git", - "reference": "a213cbc80382320b0efdccdcdce232f191fafe3a" + "reference": "b8fd0ff9a0f00d944f1534f6d21e84f92eda7258" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/a213cbc80382320b0efdccdcdce232f191fafe3a", - "reference": "a213cbc80382320b0efdccdcdce232f191fafe3a", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/b8fd0ff9a0f00d944f1534f6d21e84f92eda7258", + "reference": "b8fd0ff9a0f00d944f1534f6d21e84f92eda7258", "shasum": "" }, "require": { @@ -6660,7 +6586,7 @@ "description": "Eases DOM navigation for HTML and XML documents", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dom-crawler/tree/v5.4.9" + "source": "https://github.com/symfony/dom-crawler/tree/v5.4.15" }, "funding": [ { @@ -6676,7 +6602,7 @@ "type": "tidelift" } ], - "time": "2022-05-04T14:46:32+00:00" + "time": "2022-10-27T08:04:35+00:00" }, { "name": "theseer/tokenizer", @@ -6727,64 +6653,6 @@ } ], "time": "2021-07-28T10:34:58+00:00" - }, - { - "name": "webmozart/assert", - "version": "1.11.0", - "source": { - "type": "git", - "url": "https://github.com/webmozarts/assert.git", - "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991", - "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991", - "shasum": "" - }, - "require": { - "ext-ctype": "*", - "php": "^7.2 || ^8.0" - }, - "conflict": { - "phpstan/phpstan": "<0.12.20", - "vimeo/psalm": "<4.6.1 || 4.6.2" - }, - "require-dev": { - "phpunit/phpunit": "^8.5.13" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.10-dev" - } - }, - "autoload": { - "psr-4": { - "Webmozart\\Assert\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" - } - ], - "description": "Assertions to validate method input/output with nice error messages.", - "keywords": [ - "assert", - "check", - "validate" - ], - "support": { - "issues": "https://github.com/webmozarts/assert/issues", - "source": "https://github.com/webmozarts/assert/tree/1.11.0" - }, - "time": "2022-06-03T18:03:27+00:00" } ], "aliases": [], diff --git a/lib/SP/Core/Context/SessionContext.php b/lib/SP/Core/Context/SessionContext.php index 403aac44..7f228ba7 100644 --- a/lib/SP/Core/Context/SessionContext.php +++ b/lib/SP/Core/Context/SessionContext.php @@ -27,7 +27,7 @@ namespace SP\Core\Context; use SP\Core\Crypt\Vault; use SP\DataModel\Dto\AccountCache; use SP\DataModel\ProfileData; -use SP\Domain\Account\Services\AccountSearchFilter; +use SP\Domain\Account\Search\AccountSearchFilter; use SP\Domain\User\Services\UserLoginResponse; /** @@ -189,7 +189,7 @@ class SessionContext extends ContextBase } /** - * @param AccountSearchFilter $searchFilters + * @param \SP\Domain\Account\Search\AccountSearchFilter $searchFilters */ public function setSearchFilters(AccountSearchFilter $searchFilters): void { diff --git a/lib/SP/Core/Definitions/CoreDefinitions.php b/lib/SP/Core/Definitions/CoreDefinitions.php index 19e62c62..607319e1 100644 --- a/lib/SP/Core/Definitions/CoreDefinitions.php +++ b/lib/SP/Core/Definitions/CoreDefinitions.php @@ -24,6 +24,7 @@ namespace SP\Core\Definitions; +use Aura\SqlQuery\QueryFactory; use Monolog\Logger; use PHPMailer\PHPMailer\PHPMailer; use Psr\Container\ContainerInterface; @@ -188,6 +189,8 @@ final class CoreDefinitions $c->get(NotificationHandler::class) ); }), + QueryFactory::class => create(QueryFactory::class) + ->constructor('mysql', QueryFactory::COMMON), ]; } } \ No newline at end of file diff --git a/lib/SP/Domain/Account/AccountHistoryServiceInterface.php b/lib/SP/Domain/Account/AccountHistoryServiceInterface.php index 93ab4e2c..5b62d12d 100644 --- a/lib/SP/Domain/Account/AccountHistoryServiceInterface.php +++ b/lib/SP/Domain/Account/AccountHistoryServiceInterface.php @@ -34,6 +34,7 @@ use SP\DataModel\ItemData; use SP\DataModel\ItemSearchData; use SP\Domain\Account\Services\AccountPasswordRequest; use SP\Domain\Common\Services\ServiceException; +use SP\Infrastructure\Common\Repositories\NoSuchItemException; use SP\Infrastructure\Database\QueryResult; /** @@ -46,8 +47,7 @@ interface AccountHistoryServiceInterface /** * Returns the item for given id * - * @throws SPException - * @throws SPException + * @throws NoSuchItemException */ public function getById(int $id): AccountHistoryData; diff --git a/lib/SP/Domain/Account/AccountSearchServiceInterface.php b/lib/SP/Domain/Account/AccountSearchServiceInterface.php index f4a0fc11..a8135f93 100644 --- a/lib/SP/Domain/Account/AccountSearchServiceInterface.php +++ b/lib/SP/Domain/Account/AccountSearchServiceInterface.php @@ -28,9 +28,8 @@ namespace SP\Domain\Account; use SP\Core\Exceptions\ConstraintException; use SP\Core\Exceptions\QueryException; use SP\Core\Exceptions\SPException; -use SP\Domain\Account\Services\AccountSearchFilter; +use SP\Domain\Account\Search\AccountSearchFilter; use SP\Infrastructure\Database\QueryResult; -use SP\Mvc\Model\QueryCondition; /** * Class AccountSearchService para la gestión de búsquedas de cuentas @@ -45,13 +44,13 @@ interface AccountSearchServiceInterface * @throws QueryException * @throws SPException */ - public function processSearchResults(AccountSearchFilter $accountSearchFilter): QueryResult; + public function getByFilter(AccountSearchFilter $accountSearchFilter): QueryResult; /** * Analizar la cadena de consulta por eqituetas especiales y devolver un objeto * QueryCondition con los filtros */ - public function analyzeQueryFilters(string $string): QueryCondition; + public function analyzeQueryFilters(string $string): void; public function getCleanString(): ?string; } \ No newline at end of file diff --git a/lib/SP/Domain/Account/In/AccountRepositoryInterface.php b/lib/SP/Domain/Account/In/AccountRepositoryInterface.php index c27ac77f..9da9960c 100644 --- a/lib/SP/Domain/Account/In/AccountRepositoryInterface.php +++ b/lib/SP/Domain/Account/In/AccountRepositoryInterface.php @@ -28,9 +28,10 @@ namespace SP\Domain\Account\In; use SP\Core\Exceptions\ConstraintException; use SP\Core\Exceptions\QueryException; use SP\Core\Exceptions\SPException; +use SP\DataModel\AccountHistoryData; +use SP\Domain\Account\Search\AccountSearchFilter; use SP\Domain\Account\Services\AccountPasswordRequest; use SP\Domain\Account\Services\AccountRequest; -use SP\Domain\Account\Services\AccountSearchFilter; use SP\Domain\Common\In\RepositoryInterface; use SP\Domain\Common\Out\SimpleModel; use SP\Infrastructure\Database\QueryResult; @@ -53,22 +54,21 @@ interface AccountRepositoryInterface extends RepositoryInterface /** * @param int $id - * @param QueryCondition $queryCondition * * @return QueryResult * @throws \SP\Core\Exceptions\ConstraintException * @throws \SP\Core\Exceptions\QueryException */ - public function getPasswordForId(int $id, QueryCondition $queryCondition): QueryResult; + public function getPasswordForId(int $id): QueryResult; /** - * @param QueryCondition $queryCondition + * @param int $id * * @return QueryResult - * @throws ConstraintException - * @throws QueryException + * @throws \SP\Core\Exceptions\ConstraintException + * @throws \SP\Core\Exceptions\QueryException */ - public function getPasswordHistoryForId(QueryCondition $queryCondition): QueryResult; + public function getPasswordHistoryForId(int $id): QueryResult; /** * Incrementa el contador de vista de clave de una cuenta en la BBDD @@ -106,14 +106,14 @@ interface AccountRepositoryInterface extends RepositoryInterface /** * Restaurar una cuenta desde el histórico. * - * @param int $historyId El Id del registro en el histórico + * @param \SP\DataModel\AccountHistoryData $accountHistoryData * @param int $userId User's Id * * @return bool - * @throws ConstraintException - * @throws QueryException + * @throws \SP\Core\Exceptions\ConstraintException + * @throws \SP\Core\Exceptions\QueryException */ - public function editRestore(int $historyId, int $userId): bool; + public function editRestore(AccountHistoryData $accountHistoryData, int $userId): bool; /** * Updates an item for bulk action @@ -148,35 +148,22 @@ interface AccountRepositoryInterface extends RepositoryInterface public function getDataForLink(int $id): QueryResult; /** - * Obtener las cuentas de una búsqueda. - * - * @param AccountSearchFilter $accountSearchFilter - * @param QueryCondition $queryFilterUser + * @param int|null $accountId * * @return QueryResult - * @throws ConstraintException - * @throws QueryException - * @throws SPException + * @throws \SP\Core\Exceptions\ConstraintException + * @throws \SP\Core\Exceptions\QueryException */ - public function getByFilter(AccountSearchFilter $accountSearchFilter, QueryCondition $queryFilterUser): QueryResult; + public function getForUser(?int $accountId = null): QueryResult; /** - * @param QueryCondition $queryFilter + * @param int $accountId * * @return QueryResult - * @throws ConstraintException - * @throws QueryException + * @throws \SP\Core\Exceptions\ConstraintException + * @throws \SP\Core\Exceptions\QueryException */ - public function getForUser(QueryCondition $queryFilter): QueryResult; - - /** - * @param QueryCondition $queryFilter - * - * @return QueryResult - * @throws ConstraintException - * @throws QueryException - */ - public function getLinked(QueryCondition $queryFilter): QueryResult; + public function getLinked(int $accountId): QueryResult; /** * Obtener los datos relativos a la clave de todas las cuentas. diff --git a/lib/SP/Domain/Account/Search/AccountSearchConstants.php b/lib/SP/Domain/Account/Search/AccountSearchConstants.php new file mode 100644 index 00000000..55771394 --- /dev/null +++ b/lib/SP/Domain/Account/Search/AccountSearchConstants.php @@ -0,0 +1,56 @@ +. + */ + +namespace SP\Domain\Account\Search; + +/** + * Interface AccountSearchConstants + */ +interface AccountSearchConstants +{ + public const FILTER_OWNER = 'owner'; + public const FILTER_MAIN_GROUP = 'mainGroup'; + public const FILTER_CATEGORY_NAME = 'categoryName'; + public const FILTER_FILE_NAME = 'fileName'; + public const FILTER_ACCOUNT_ID = 'accountId'; + public const FILTER_USER_NAME = 'userName'; + public const FILTER_ACCOUNT_NAME_REGEX = 'accountNameRegex'; + public const FILTER_CLIENT_NAME = 'clientName'; + public const FILTER_GROUP_NAME = 'groupName'; + public const FILTER_CHAIN_AND = 'and'; + public const FILTER_CHAIN_OR = 'or'; + public const FILTER_IS_PRIVATE = 'is:private'; + public const FILTER_NOT_PRIVATE = 'not:private'; + public const FILTER_IS_EXPIRED = 'is:expired'; + public const FILTER_NOT_EXPIRED = 'is:expired'; + + public const SORT_DIR_ASC = 0; + public const SORT_DIR_DESC = 1; + public const SORT_CATEGORY = 2; + public const SORT_DEFAULT = 0; + public const SORT_LOGIN = 3; + public const SORT_URL = 4; + public const SORT_NAME = 1; + public const SORT_CLIENT = 5; +} \ No newline at end of file diff --git a/lib/SP/Domain/Account/Services/AccountSearchFilter.php b/lib/SP/Domain/Account/Search/AccountSearchFilter.php similarity index 65% rename from lib/SP/Domain/Account/Services/AccountSearchFilter.php rename to lib/SP/Domain/Account/Search/AccountSearchFilter.php index 20306bf8..9818c390 100644 --- a/lib/SP/Domain/Account/Services/AccountSearchFilter.php +++ b/lib/SP/Domain/Account/Search/AccountSearchFilter.php @@ -22,7 +22,7 @@ * along with sysPass. If not, see . */ -namespace SP\Domain\Account\Services; +namespace SP\Domain\Account\Search; use SP\Mvc\Model\QueryCondition; @@ -30,21 +30,19 @@ use SP\Mvc\Model\QueryCondition; /** * Class AccountSearchFilter * - * @package SP\Account + * @package SP\Domain\Account\Filters */ final class AccountSearchFilter { /** - * Constantes de ordenación + * @param string $txtSearch + * + * @return \SP\Domain\Account\Search\AccountSearchFilter */ - public const SORT_DIR_ASC = 0; - public const SORT_DIR_DESC = 1; - public const SORT_LOGIN = 3; - public const SORT_URL = 4; - public const SORT_CATEGORY = 2; - public const SORT_CLIENT = 5; - public const SORT_NAME = 1; - public const SORT_DEFAULT = 0; + public static function build(string $txtSearch): AccountSearchFilter + { + return (new self())->setTxtSearch($txtSearch); + } /** * @var int|null El número de registros de la última consulta @@ -55,18 +53,17 @@ final class AccountSearchFilter /** * @var string|null Search string without special filters */ - private ?string $cleanTxtSearch = null; - private ?int $clientId = null; - private ?int $categoryId = null; - private ?array $tagsId = null; - private int $sortOrder = self::SORT_DEFAULT; - private int $sortKey = self::SORT_DIR_ASC; - private int $limitStart = 0; - private ?int $limitCount = null; - private ?bool $sortViews = null; - private bool $searchFavorites = false; - private ?QueryCondition $stringFilters = null; - private ?string $filterOperator = null; + private ?string $cleanTxtSearch = null; + private ?int $clientId = null; + private ?int $categoryId = null; + private ?array $tagsId = null; + private int $sortOrder = AccountSearchConstants::SORT_DEFAULT; + private int $sortKey = AccountSearchConstants::SORT_DIR_ASC; + private int $limitStart = 0; + private ?int $limitCount = null; + private ?bool $sortViews = null; + private bool $searchFavorites = false; + private ?string $filterOperator = null; public function isSearchFavorites(): bool { @@ -181,57 +178,6 @@ final class AccountSearchFilter return null !== $this->tagsId && count($this->tagsId) !== 0; } - public function getStringFilters(): QueryCondition - { - return $this->stringFilters ?? new QueryCondition(); - } - - public function setStringFilters(?QueryCondition $stringFilters): void - { - $this->stringFilters = $stringFilters; - } - - /** - * Devuelve la cadena de ordenación de la consulta - */ - public function getOrderString(): string - { - switch ($this->sortKey) { - case self::SORT_NAME: - $orderKey[] = 'Account.name'; - break; - case self::SORT_CATEGORY: - $orderKey[] = 'Account.categoryName'; - break; - case self::SORT_LOGIN: - $orderKey[] = 'Account.login'; - break; - case self::SORT_URL: - $orderKey[] = 'Account.url'; - break; - case self::SORT_CLIENT: - $orderKey[] = 'Account.clientName'; - break; - case self::SORT_DEFAULT: - default: - $orderKey[] = 'Account.clientName, Account.name'; - break; - } - - if ($this->isSortViews() && !$this->getSortKey()) { - array_unshift($orderKey, 'Account.countView DESC'); - $this->setSortOrder(self::SORT_DIR_DESC); - } - - $orderDir = $this->sortOrder === self::SORT_DIR_ASC ? 'ASC' : 'DESC'; - - return sprintf( - '%s %s', - implode(',', $orderKey), - $orderDir - ); - } - public function isSortViews(): bool { return $this->sortViews ?? false; @@ -292,7 +238,7 @@ final class AccountSearchFilter $this->limitCount = null; $this->sortViews = null; $this->searchFavorites = false; - $this->sortOrder = self::SORT_DEFAULT; - $this->sortKey = self::SORT_DIR_ASC; + $this->sortOrder = AccountSearchConstants::SORT_DEFAULT; + $this->sortKey = AccountSearchConstants::SORT_DIR_ASC; } } \ No newline at end of file diff --git a/lib/SP/Domain/Account/Search/AccountSearchTokenizer.php b/lib/SP/Domain/Account/Search/AccountSearchTokenizer.php new file mode 100644 index 00000000..2faa9f55 --- /dev/null +++ b/lib/SP/Domain/Account/Search/AccountSearchTokenizer.php @@ -0,0 +1,148 @@ +. + */ + +namespace SP\Domain\Account\Search; + +use SP\Util\Filter; + +/** + * Class AccountSearchTokenizer + */ +final class AccountSearchTokenizer +{ + private const SEARCH_REGEX = /** @lang RegExp */ + '/(?(?[a-zа-я_]+):(?!\s]*)"?(?[^":]+)"?/u'; + + private const FILTERS = [ + 'condition' => [ + 'subject' => ['is', 'not'], + 'condition' => ['expired', 'private'], + ], + 'items' => [ + 'subject' => [ + 'id' => AccountSearchConstants::FILTER_ACCOUNT_ID, + 'user' => AccountSearchConstants::FILTER_USER_NAME, + 'group' => AccountSearchConstants::FILTER_GROUP_NAME, + 'file' => AccountSearchConstants::FILTER_FILE_NAME, + 'owner' => AccountSearchConstants::FILTER_OWNER, + 'maingroup' => AccountSearchConstants::FILTER_MAIN_GROUP, + 'client' => AccountSearchConstants::FILTER_CLIENT_NAME, + 'category' => AccountSearchConstants::FILTER_CATEGORY_NAME, + 'name_regex' => AccountSearchConstants::FILTER_ACCOUNT_NAME_REGEX, + ], + 'condition' => null, + ], + 'operator' => [ + 'subject' => ['op'], + 'condition' => [AccountSearchConstants::FILTER_CHAIN_AND, AccountSearchConstants::FILTER_CHAIN_OR], + ], + ]; + + /** + * @param string $search + * + * @return AccountSearchTokens|null + */ + public function tokenizeFrom(string $search): ?AccountSearchTokens + { + $match = preg_match_all(self::SEARCH_REGEX, $search, $filters); + + if (empty($match)) { + return null; + } + + $filtersAndValues = array_filter(array_combine($filters['filter_subject'], $filters['filter_condition'])); + + return new AccountSearchTokens( + Filter::safeSearchString(trim($filters['search'][0] ?? '')), + $this->getConditions($filtersAndValues), + $this->getItems($filtersAndValues), + $this->getOperator($filtersAndValues)[0], + ); + } + + /** + * @param array $filters + * + * @return array + */ + private function getConditions(array $filters): array + { + return array_filter( + array_map( + static function ($subject, $condition) { + if (in_array($subject, self::FILTERS['condition']['subject'], true) + && in_array($condition, self::FILTERS['condition']['condition'], true) + ) { + return sprintf("%s:%s", $subject, $condition); + } + + return null; + }, + $filters['filter_subject'], + $filters['filter_condition'] + ) + ); + } + + /** + * @param array $filtersAndValues + * + * @return array + */ + private function getItems(array $filtersAndValues): array + { + $items = array_filter( + $filtersAndValues, + static function ($value, $key) { + return in_array($key, array_keys(self::FILTERS['items']['subject']), true) && !empty($value); + }, + ARRAY_FILTER_USE_BOTH + ); + + return array_combine( + array_map(function ($key) { + return self::FILTERS['items']['subject'][$key]; + }, array_keys($items)), + array_values($items) + ); + } + + /** + * @param array $filtersAndValues + * + * @return array + */ + private function getOperator(array $filtersAndValues): array + { + return array_filter( + $filtersAndValues, + static function ($value, $key) { + return in_array($key, self::FILTERS['operator']['subject'], true) + && in_array($value, self::FILTERS['operator']['condition'], true); + }, + ARRAY_FILTER_USE_BOTH + ); + } +} \ No newline at end of file diff --git a/lib/SP/Domain/Account/Search/AccountSearchTokens.php b/lib/SP/Domain/Account/Search/AccountSearchTokens.php new file mode 100644 index 00000000..c58cbb3c --- /dev/null +++ b/lib/SP/Domain/Account/Search/AccountSearchTokens.php @@ -0,0 +1,70 @@ +. + */ + +namespace SP\Domain\Account\Search; + +/** + * Class AccountSearchTokens + */ +final class AccountSearchTokens +{ + private string $search; + private array $conditions; + private array $items; + private string $operator; + + /** + * @param string $search + * @param array $conditions + * @param array $items + * @param string $operator + */ + public function __construct(string $search, array $conditions, array $items, string $operator) + { + $this->search = $search; + $this->conditions = $conditions; + $this->items = $items; + $this->operator = $operator; + } + + public function getConditions(): array + { + return $this->conditions; + } + + public function getItems(): array + { + return $this->items; + } + + public function getOperator(): string + { + return $this->operator; + } + + public function getSearch(): string + { + return $this->search; + } +} \ No newline at end of file diff --git a/lib/SP/Domain/Account/Services/AccountFilterUser.php b/lib/SP/Domain/Account/Services/AccountFilterUser.php index e46d4f43..84c58b4b 100644 --- a/lib/SP/Domain/Account/Services/AccountFilterUser.php +++ b/lib/SP/Domain/Account/Services/AccountFilterUser.php @@ -24,128 +24,137 @@ namespace SP\Domain\Account\Services; +use Aura\SqlQuery\Common\SelectInterface; +use Aura\SqlQuery\QueryFactory; use SP\Core\Context\ContextInterface; use SP\DataModel\ProfileData; +use SP\Domain\Account\Search\AccountSearchConstants; use SP\Domain\Config\In\ConfigDataInterface; use SP\Domain\User\Services\UserLoginResponse; -use SP\Mvc\Model\QueryCondition; defined('APP_ROOT') || die(); /** - * Class AccountUtil con utilidades para la gestión de cuentas + * Class AccountFilterUser */ final class AccountFilterUser { private ConfigDataInterface $configData; private ContextInterface $context; - private ?ProfileData $userProfile = null; - private ?UserLoginResponse $userData = null; + private QueryFactory $queryFactory; public function __construct( ContextInterface $context, - ConfigDataInterface $configData + ConfigDataInterface $configData, + QueryFactory $queryFactory ) { $this->context = $context; $this->configData = $configData; + $this->queryFactory = $queryFactory; } /** * Devuelve el filtro para la consulta SQL de cuentas que un usuario puede acceder */ - public function getFilterHistory(bool $useGlobalSearch = false): QueryCondition + public function buildFilterHistory(bool $useGlobalSearch = false, ?SelectInterface $query = null): SelectInterface { - $this->setUp(); + $userData = $this->context->getUserData(); + $userProfile = $this->context->getUserProfile(); - $queryFilter = new QueryCondition(); + if ($query === null) { + $query = $this->queryFactory->newSelect()->from('AccountHistory'); + } - if (!$this->userData->getIsAdminApp() - && !$this->userData->getIsAdminAcc() - && !($this->configData->isGlobalSearch() && $useGlobalSearch && $this->userProfile->isAccGlobalSearch()) - ) { - // Filtro usuario y grupo - $filter = '(AccountHistory.userId = ? - OR AccountHistory.userGroupId = ? - OR AccountHistory.accountId IN (SELECT accountId AS accountId FROM AccountToUser WHERE accountId = AccountHistory.accountId AND userId = ? UNION ALL SELECT accountId FROM AccountToUserGroup WHERE accountId = AccountHistory.accountId AND userGroupId = ?) - OR AccountHistory.userGroupId IN (SELECT userGroupId FROM UserToUserGroup WHERE userGroupId = AccountHistory.userGroupId AND userId = ?))'; - - $params = [ - $this->userData->getId(), - $this->userData->getUserGroupId(), - $this->userData->getId(), - $this->userData->getUserGroupId(), - $this->userData->getId(), + if ($this->isFilterByAdminAndGlobalSearch($userData, $useGlobalSearch, $userProfile)) { + $where = [ + 'AccountHistory.userId = :userId', + 'AccountHistory.userGroupId = :userGroupId', + 'AccountHistory.accountId IN (SELECT accountId AS accountId FROM AccountToUser WHERE accountId = AccountHistory.accountId AND userId = :userId UNION ALL SELECT accountId FROM AccountToUserGroup WHERE accountId = AccountHistory.accountId AND userGroupId = :userGroupId', + 'AccountHistory.userGroupId IN (SELECT userGroupId FROM UserToUserGroup WHERE userGroupId = AccountHistory.userGroupId AND userId = :userId)', ]; if ($this->configData->isAccountFullGroupAccess()) { // Filtro de grupos secundarios en grupos que incluyen al usuario - $filter .= PHP_EOL - .'OR AccountHistory.accountId = (SELECT accountId FROM AccountToUserGroup aug INNER JOIN UserToUserGroup uug ON uug.userGroupId = aug.userGroupId WHERE aug.accountId = AccountHistory.accountId AND uug.userId = ? LIMIT 1)'; - $params[] = $this->userData->getId(); + $where[] = + 'AccountHistory.accountId = (SELECT accountId FROM AccountToUserGroup aug INNER JOIN UserToUserGroup uug ON uug.userGroupId = aug.userGroupId WHERE aug.accountId = AccountHistory.accountId AND uug.userId = :userId LIMIT 1)'; } - $queryFilter->addFilter($filter, $params); + $query->where(sprintf('(%s)', join(sprintf(' %s ', AccountSearchConstants::FILTER_CHAIN_OR), $where))); } - $queryFilter->addFilter( - '(AccountHistory.isPrivate IS NULL OR AccountHistory.isPrivate = 0 OR (AccountHistory.isPrivate = 1 AND AccountHistory.userId = ?)) AND (AccountHistory.isPrivateGroup IS NULL OR AccountHistory.isPrivateGroup = 0 OR (AccountHistory.isPrivateGroup = 1 AND AccountHistory.userGroupId = ?))', - [$this->userData->getId(), $this->userData->getUserGroupId()] + $query->where( + '(AccountHistory.isPrivate IS NULL OR AccountHistory.isPrivate = 0 OR (AccountHistory.isPrivate = 1 AND AccountHistory.userId = :userId))' + ); + $query->where( + '(AccountHistory.isPrivateGroup IS NULL OR AccountHistory.isPrivateGroup = 0 OR (AccountHistory.isPrivateGroup = 1 AND AccountHistory.userGroupId = :userGroupId))' ); - return $queryFilter; - } + $query->bindValues([ + 'userId' => $userData->getId(), + 'userGroupId' => $userData->getUserGroupId(), + ]); - /** - * setUp - */ - private function setUp(): void - { - $this->userData = $this->context->getUserData(); - $this->userProfile = $this->context->getUserProfile(); + return $query; } /** * Devuelve el filtro para la consulta SQL de cuentas que un usuario puede acceder */ - public function getFilter(bool $useGlobalSearch = false): QueryCondition + public function buildFilter(bool $useGlobalSearch = false, ?SelectInterface $query = null): SelectInterface { - $this->setUp(); + $userData = $this->context->getUserData(); + $userProfile = $this->context->getUserProfile(); - $queryFilter = new QueryCondition(); + if ($query === null) { + $query = $this->queryFactory->newSelect()->from('Account'); + } - if (!$this->userData->getIsAdminApp() - && !$this->userData->getIsAdminAcc() - && !($this->configData->isGlobalSearch() && $useGlobalSearch && $this->userProfile->isAccGlobalSearch()) - ) { - // Filtro usuario y grupo - $filter = '(Account.userId = ? - OR Account.userGroupId = ? - OR Account.id IN (SELECT accountId AS accountId FROM AccountToUser WHERE accountId = Account.id AND userId = ? UNION ALL SELECT accountId FROM AccountToUserGroup WHERE accountId = Account.id AND userGroupId = ?) - OR Account.userGroupId IN (SELECT userGroupId FROM UserToUserGroup WHERE userGroupId = Account.userGroupId AND userId = ?))'; - - $params = [ - $this->userData->getId(), - $this->userData->getUserGroupId(), - $this->userData->getId(), - $this->userData->getUserGroupId(), - $this->userData->getId(), + if ($this->isFilterByAdminAndGlobalSearch($userData, $useGlobalSearch, $userProfile)) { + $where = [ + 'Account.userId = :userId', + 'Account.userGroupId = :userGroupId', + 'Account.id IN (SELECT accountId AS accountId FROM AccountToUser WHERE accountId = Account.id AND userId = :userId UNION ALL SELECT accountId FROM AccountToUserGroup WHERE accountId = Account.id AND userGroupId = :userGroupId)', + 'Account.userGroupId IN (SELECT userGroupId FROM UserToUserGroup WHERE userGroupId = Account.userGroupId AND userId = :userId)', ]; if ($this->configData->isAccountFullGroupAccess()) { // Filtro de grupos secundarios en grupos que incluyen al usuario - $filter .= PHP_EOL - .'OR Account.id = (SELECT accountId FROM AccountToUserGroup aug INNER JOIN UserToUserGroup uug ON uug.userGroupId = aug.userGroupId WHERE aug.accountId = Account.id AND uug.userId = ? LIMIT 1)'; - $params[] = $this->userData->getId(); + $where[] = + 'Account.id = (SELECT accountId FROM AccountToUserGroup aug INNER JOIN UserToUserGroup uug ON uug.userGroupId = aug.userGroupId WHERE aug.accountId = Account.id AND uug.userId = :userId LIMIT 1)'; } - $queryFilter->addFilter($filter, $params); + $query->where(sprintf('(%s)', join(sprintf(' %s ', AccountSearchConstants::FILTER_CHAIN_OR), $where))); } - $queryFilter->addFilter( - '(Account.isPrivate IS NULL OR Account.isPrivate = 0 OR (Account.isPrivate = 1 AND Account.userId = ?)) AND (Account.isPrivateGroup IS NULL OR Account.isPrivateGroup = 0 OR (Account.isPrivateGroup = 1 AND Account.userGroupId = ?))', - [$this->userData->getId(), $this->userData->getUserGroupId()] + $query->where( + 'Account.isPrivate IS NULL OR Account.isPrivate = 0 OR (Account.isPrivate = 1 AND Account.userId = :userId)' + ); + $query->where( + 'Account.isPrivateGroup IS NULL OR Account.isPrivateGroup = 0 OR (Account.isPrivateGroup = 1 AND Account.userGroupId = :userGroupId)' ); - return $queryFilter; + $query->bindValues([ + 'userId' => $userData->getId(), + 'userGroupId' => $userData->getUserGroupId(), + ]); + + return $query; + } + + /** + * @param \SP\Domain\User\Services\UserLoginResponse $userData + * @param bool $useGlobalSearch + * @param \SP\DataModel\ProfileData|null $userProfile + * + * @return bool + */ + private function isFilterByAdminAndGlobalSearch( + UserLoginResponse $userData, + bool $useGlobalSearch, + ?ProfileData $userProfile + ): bool { + return !$userData->getIsAdminApp() + && !$userData->getIsAdminAcc() + && !($this->configData->isGlobalSearch() && $useGlobalSearch && $userProfile->isAccGlobalSearch()); } } \ No newline at end of file diff --git a/lib/SP/Domain/Account/Services/AccountHistoryService.php b/lib/SP/Domain/Account/Services/AccountHistoryService.php index 86e84c78..b8022fa9 100644 --- a/lib/SP/Domain/Account/Services/AccountHistoryService.php +++ b/lib/SP/Domain/Account/Services/AccountHistoryService.php @@ -68,8 +68,7 @@ final class AccountHistoryService extends Service implements AccountHistoryServi /** * Returns the item for given id * - * @throws SPException - * @throws SPException + * @throws NoSuchItemException */ public function getById(int $id): AccountHistoryData { diff --git a/lib/SP/Domain/Account/Services/AccountSearchService.php b/lib/SP/Domain/Account/Services/AccountSearchService.php index 19b6f1a9..1eb9239c 100644 --- a/lib/SP/Domain/Account/Services/AccountSearchService.php +++ b/lib/SP/Domain/Account/Services/AccountSearchService.php @@ -36,19 +36,21 @@ use SP\DataModel\Dto\AccountCache; use SP\Domain\Account\AccountAclServiceInterface; use SP\Domain\Account\AccountSearchServiceInterface; use SP\Domain\Account\AccountToFavoriteServiceInterface; -use SP\Domain\Account\In\AccountRepositoryInterface; use SP\Domain\Account\In\AccountToTagRepositoryInterface; use SP\Domain\Account\In\AccountToUserGroupRepositoryInterface; use SP\Domain\Account\In\AccountToUserRepositoryInterface; +use SP\Domain\Account\Search\AccountSearchConstants; +use SP\Domain\Account\Search\AccountSearchFilter; +use SP\Domain\Account\Search\AccountSearchTokenizer; use SP\Domain\Common\Services\Service; use SP\Domain\Config\In\ConfigDataInterface; use SP\Domain\User\UserGroupServiceInterface; use SP\Domain\User\UserServiceInterface; +use SP\Infrastructure\Account\Repositories\AccountSearchRepositoryInterface; use SP\Infrastructure\Database\QueryResult; use SP\Infrastructure\File\FileCache; use SP\Infrastructure\File\FileCacheInterface; use SP\Infrastructure\File\FileException; -use SP\Mvc\Model\QueryCondition; use SP\Util\Filter; defined('APP_ROOT') || die(); @@ -58,24 +60,6 @@ defined('APP_ROOT') || die(); */ final class AccountSearchService extends Service implements AccountSearchServiceInterface { - /** - * Regex filters for special searching - */ - private const FILTERS = [ - 'condition' => [ - 'subject' => ['is', 'not'], - 'condition' => ['expired', 'private'], - ], - 'items' => [ - 'subject' => ['id', 'user', 'group', 'file', 'owner', 'maingroup', 'client', 'category', 'name_regex'], - 'condition' => null, - ], - 'operator' => [ - 'subject' => ['op'], - 'condition' => ['and', 'or'], - ], - ]; - private const COLORS_CACHE_FILE = CACHE_PATH.DIRECTORY_SEPARATOR.'colors.cache'; /** @@ -100,7 +84,6 @@ final class AccountSearchService extends Service implements AccountSearchService '673AB7', '3F51B5', ]; - private AccountFilterUser $accountFilterUser; private AccountAclServiceInterface $accountAclService; private ConfigDataInterface $configData; private AccountToTagRepositoryInterface $accountToTagRepository; @@ -110,7 +93,7 @@ final class AccountSearchService extends Service implements AccountSearchService private UserServiceInterface $userService; private UserGroupServiceInterface $userGroupService; private FileCacheInterface $colorCache; - private AccountRepositoryInterface $accountRepository; + private AccountSearchRepositoryInterface $accountSearchRepository; private ?array $accountColor = null; private ?string $cleanString = null; private ?string $filterOperator = null; @@ -124,8 +107,7 @@ final class AccountSearchService extends Service implements AccountSearchService AccountToFavoriteServiceInterface $accountToFavoriteService, UserServiceInterface $userService, UserGroupServiceInterface $userGroupService, - AccountRepositoryInterface $accountRepository, - AccountFilterUser $accountFilterUser + AccountSearchRepositoryInterface $accountSearchRepository, ) { parent::__construct($application); $this->accountAclService = $accountAclService; @@ -135,8 +117,7 @@ final class AccountSearchService extends Service implements AccountSearchService $this->accountToTagRepository = $accountToTagRepository; $this->accountToUserRepository = $accountToUserRepository; $this->accountToUserGroupRepository = $accountToUserGroupRepository; - $this->accountRepository = $accountRepository; - $this->accountFilterUser = $accountFilterUser; + $this->accountSearchRepository = $accountSearchRepository; // TODO: use IoC $this->colorCache = new FileCache(self::COLORS_CACHE_FILE); @@ -168,16 +149,13 @@ final class AccountSearchService extends Service implements AccountSearchService * @throws QueryException * @throws SPException */ - public function processSearchResults( - AccountSearchFilter $accountSearchFilter - ): QueryResult { + public function getByFilter(AccountSearchFilter $accountSearchFilter): QueryResult + { if (!empty($accountSearchFilter->getTxtSearch())) { - $accountSearchFilter->setStringFilters($this->analyzeQueryFilters($accountSearchFilter->getTxtSearch())); + $this->analyzeQueryFilters($accountSearchFilter->getTxtSearch()); } - if ($this->filterOperator !== null - || $accountSearchFilter->getFilterOperator() === null - ) { + if ($this->filterOperator !== null || $accountSearchFilter->getFilterOperator() === null) { $accountSearchFilter->setFilterOperator($this->filterOperator); } @@ -185,224 +163,65 @@ final class AccountSearchService extends Service implements AccountSearchService $accountSearchFilter->setCleanTxtSearch($this->cleanString); } - $queryResult = $this->accountRepository->getByFilter( - $accountSearchFilter, - $this->accountFilterUser->getFilter($accountSearchFilter->getGlobalSearch()) - ); + $queryResult = $this->accountSearchRepository->getByFilter($accountSearchFilter); - // Variables de configuración - $maxTextLength = $this->configData->isResultsAsCards() ? 40 : 60; - - $accountLinkEnabled = $this->context->getUserData()->getPreferences()->isAccountLink() - || $this->configData->isAccountLink(); - $favorites = $this->accountToFavoriteService->getForUserId($this->context->getUserData()->getId()); - - $accountsData = []; - - /** @var AccountSearchVData $accountSearchData */ - foreach ($queryResult->getDataAsArray() as $accountSearchData) { - $cache = $this->getCacheForAccount($accountSearchData); - - // Obtener la ACL de la cuenta - $accountAcl = $this->accountAclService->getAcl( - ActionsInterface::ACCOUNT_SEARCH, - AccountAclDto::makeFromAccountSearch( - $accountSearchData, - $cache->getUsers(), - $cache->getUserGroups() - ) - ); - - // Propiedades de búsqueda de cada cuenta - $accountsSearchItem = new AccountSearchItem( - $accountSearchData, - $accountAcl, - $this->configData - ); - - if (!$accountSearchData->getIsPrivate()) { - $accountsSearchItem->setUsers($cache->getUsers()); - $accountsSearchItem->setUserGroups($cache->getUserGroups()); - } - - $accountsSearchItem->setTags( - $this->accountToTagRepository - ->getTagsByAccountId($accountSearchData->getId()) - ->getDataAsArray() - ); - $accountsSearchItem->setTextMaxLength($maxTextLength); - $accountsSearchItem->setColor( - $this->pickAccountColor($accountSearchData->getClientId()) - ); - $accountsSearchItem->setLink($accountLinkEnabled); - $accountsSearchItem->setFavorite( - isset($favorites[$accountSearchData->getId()]) - ); - - $accountsData[] = $accountsSearchItem; - } - - return QueryResult::fromResults($accountsData, $queryResult->getTotalNumRows()); + return QueryResult::fromResults($this->buildAccountsData($queryResult), $queryResult->getTotalNumRows()); } /** * Analizar la cadena de consulta por eqituetas especiales y devolver un objeto * QueryCondition con los filtros */ - public function analyzeQueryFilters(string $string): QueryCondition + public function analyzeQueryFilters(string $string): void { - $this->cleanString = null; - $this->filterOperator = null; + $tokenizer = new AccountSearchTokenizer(); + $tokens = $tokenizer->tokenizeFrom($string); - $queryCondition = new QueryCondition(); + $this->cleanString = $tokens->getSearch(); + $this->filterOperator = $tokens->getOperator(); - $match = preg_match_all( - '/(?(?[a-zа-я_]+):(?!\s]*)"?(?[^":]+)"?/u', - $string, - $filters - ); - - if ($match !== false && $match > 0) { - if (!empty($filters['search'][0])) { - $this->cleanString = Filter::safeSearchString(trim($filters['search'][0])); - } - - $filtersAndValues = array_filter( - array_combine( - $filters['filter_subject'], - $filters['filter_condition'] - ) - ); - - if (!empty($filtersAndValues)) { - $filtersItem = array_filter( - $filtersAndValues, - static function ($value, $key) { - return in_array($key, self::FILTERS['items']['subject'], true) - && $value !== ''; - }, - ARRAY_FILTER_USE_BOTH - ); - - if (!empty($filtersItem)) { - $this->processFilterItems($filtersItem, $queryCondition); - } - - $filtersOperator = array_filter( - $filtersAndValues, - static function ($value, $key) { - return in_array($key, self::FILTERS['operator']['subject'], true) - && in_array($value, self::FILTERS['operator']['condition'], true); - }, - ARRAY_FILTER_USE_BOTH - ); - - if (!empty($filtersOperator)) { - $this->processFilterOperator($filtersOperator); - } - - $filtersCondition = array_filter( - array_map( - static function ($subject, $condition) { - if (in_array($subject, self::FILTERS['condition']['subject'], true) - && in_array($condition, self::FILTERS['condition']['condition'], true) - ) { - return $subject.':'.$condition; - } - - return null; - }, - $filters['filter_subject'], - $filters['filter_condition'] - ) - ); - - if (count($filtersCondition) !== 0) { - $this->processFilterIs($filtersCondition, $queryCondition); - } - } - } - - return $queryCondition; + $this->processFilterItems($tokens->getItems()); + $this->processFilterConditions($tokens->getConditions()); } - private function processFilterItems( - array $filters, - QueryCondition $queryCondition - ): void { + private function processFilterItems(array $filters): void + { foreach ($filters as $filter => $text) { try { switch ($filter) { - case 'user': + case AccountSearchConstants::FILTER_USER_NAME: $userData = $this->userService->getByLogin(Filter::safeSearchString($text)); - if (null !== $userData) { - $queryCondition->addFilter( - 'Account.userId = ? OR Account.userGroupId = ? OR Account.id IN - (SELECT AccountToUser.accountId FROM AccountToUser WHERE AccountToUser.accountId = Account.id AND AccountToUser.userId = ? - UNION - SELECT AccountToUserGroup.accountId FROM AccountToUserGroup WHERE AccountToUserGroup.accountId = Account.id AND AccountToUserGroup.userGroupId = ?)', - [ - $userData->getId(), - $userData->getUserGroupId(), - $userData->getId(), - $userData->getUserGroupId(), - ] - ); - } - break; - case 'owner': - $text = '%'.Filter::safeSearchString($text).'%'; - $queryCondition->addFilter( - 'Account.userLogin LIKE ? OR Account.userName LIKE ?', - [$text, $text] + $this->accountSearchRepository->withFilterForUser( + $userData->getId(), + $userData->getUserGroupId() ); break; - case 'group': + case AccountSearchConstants::FILTER_OWNER: + $this->accountSearchRepository->withFilterForOwner($text); + break; + case AccountSearchConstants::FILTER_GROUP_NAME: $userGroupData = $this->userGroupService->getByName(Filter::safeSearchString($text)); - if (is_object($userGroupData)) { - $queryCondition->addFilter( - 'Account.userGroupId = ? OR Account.id IN (SELECT AccountToUserGroup.accountId FROM AccountToUserGroup WHERE AccountToUserGroup.accountId = id AND AccountToUserGroup.userGroupId = ?)', - [$userGroupData->getId(), $userGroupData->getId()] - ); - } + $this->accountSearchRepository->withFilterForGroup($userGroupData->getId()); break; - case 'maingroup': - $queryCondition->addFilter( - 'Account.userGroupName LIKE ?', - ['%'.Filter::safeSearchString($text).'%'] - ); + case AccountSearchConstants::FILTER_MAIN_GROUP: + $this->accountSearchRepository->withFilterForMainGroup($text); break; - case 'file': - $queryCondition->addFilter( - 'Account.id IN (SELECT AccountFile.accountId FROM AccountFile WHERE AccountFile.name LIKE ?)', - ['%'.$text.'%'] - ); + case AccountSearchConstants::FILTER_FILE_NAME: + $this->accountSearchRepository->withFilterForFile($text); break; - case 'id': - $queryCondition->addFilter( - 'Account.id = ?', - [(int)$text] - ); + case AccountSearchConstants::FILTER_ACCOUNT_ID: + $this->accountSearchRepository->withFilterForAccountId((int)$text); break; - case 'client': - $queryCondition->addFilter( - 'Account.clientName LIKE ?', - ['%'.Filter::safeSearchString($text).'%'] - ); + case AccountSearchConstants::FILTER_CLIENT_NAME: + $this->accountSearchRepository->withFilterForClient($text); break; - case 'category': - $queryCondition->addFilter( - 'Account.categoryName LIKE ?', - ['%'.Filter::safeSearchString($text).'%'] - ); + case AccountSearchConstants::FILTER_CATEGORY_NAME: + $this->accountSearchRepository->withFilterForCategory($text); break; - case 'name_regex': - $queryCondition->addFilter( - 'Account.name REGEXP ?', - [$text] - ); + case AccountSearchConstants::FILTER_ACCOUNT_NAME_REGEX: + $this->accountSearchRepository->withFilterForAccountNameRegex($text); break; } } catch (Exception $e) { @@ -411,46 +230,24 @@ final class AccountSearchService extends Service implements AccountSearchService } } - private function processFilterOperator(array $filters): void + private function processFilterConditions(array $filters,): void { - switch ($filters['op']) { - case 'and': - $this->filterOperator = QueryCondition::CONDITION_AND; - break; - case 'or': - $this->filterOperator = QueryCondition::CONDITION_OR; - break; - } - } - - private function processFilterIs( - array $filters, - QueryCondition $queryCondition - ): void { foreach ($filters as $filter) { switch ($filter) { - case 'is:expired': - $queryCondition->addFilter( - 'Account.passDateChange > 0 AND UNIX_TIMESTAMP() > Account.passDateChange', - [] + case AccountSearchConstants::FILTER_IS_EXPIRED: + $this->accountSearchRepository->withFilterForIsExpired(); + break; + case AccountSearchConstants::FILTER_NOT_EXPIRED: + $this->accountSearchRepository->withFilterForIsNotExpired(); + break; + case AccountSearchConstants::FILTER_IS_PRIVATE: + $this->accountSearchRepository->withFilterForIsPrivate( + $this->context->getUserData()->getId(), + $this->context->getUserData()->getUserGroupId() ); break; - case 'not:expired': - $queryCondition->addFilter( - 'Account.passDateChange = 0 OR Account.passDateChange IS NULL OR UNIX_TIMESTAMP() < Account.passDateChange', - [] - ); - break; - case 'is:private': - $queryCondition->addFilter( - '(Account.isPrivate = 1 AND Account.userId = ?) OR (Account.isPrivateGroup = 1 AND Account.userGroupId = ?)', - [$this->context->getUserData()->getId(), $this->context->getUserData()->getUserGroupId()] - ); - break; - case 'not:private': - $queryCondition->addFilter( - '(Account.isPrivate = 0 OR Account.isPrivate IS NULL) AND (Account.isPrivateGroup = 0 OR Account.isPrivateGroup IS NULL)' - ); + case AccountSearchConstants::FILTER_NOT_PRIVATE: + $this->accountSearchRepository->withFilterForIsNotPrivate(); break; } } @@ -462,9 +259,8 @@ final class AccountSearchService extends Service implements AccountSearchService * @throws ConstraintException * @throws QueryException */ - protected function getCacheForAccount( - AccountSearchVData $accountSearchData - ): AccountCache { + private function getCacheForAccount(AccountSearchVData $accountSearchData): AccountCache + { $accountId = $accountSearchData->getId(); /** @var AccountCache[] $cache */ @@ -522,4 +318,65 @@ final class AccountSearchService extends Service implements AccountSearchService { return $this->cleanString; } + + /** + * @param \SP\Infrastructure\Database\QueryResult $queryResult + * + * @return array + * @throws \SP\Core\Exceptions\ConstraintException + * @throws \SP\Core\Exceptions\QueryException + */ + private function buildAccountsData(QueryResult $queryResult): array + { + $maxTextLength = $this->configData->isResultsAsCards() ? 40 : 60; + $accountLinkEnabled = $this->context->getUserData()->getPreferences()->isAccountLink() + || $this->configData->isAccountLink(); + $favorites = $this->accountToFavoriteService->getForUserId($this->context->getUserData()->getId()); + $accountsData = []; + + /** @var AccountSearchVData $accountSearchData */ + foreach ($queryResult->getDataAsArray() as $accountSearchData) { + $cache = $this->getCacheForAccount($accountSearchData); + + // Obtener la ACL de la cuenta + $accountAcl = $this->accountAclService->getAcl( + ActionsInterface::ACCOUNT_SEARCH, + AccountAclDto::makeFromAccountSearch( + $accountSearchData, + $cache->getUsers(), + $cache->getUserGroups() + ) + ); + + // Propiedades de búsqueda de cada cuenta + $accountsSearchItem = new AccountSearchItem( + $accountSearchData, + $accountAcl, + $this->configData + ); + + if (!$accountSearchData->getIsPrivate()) { + $accountsSearchItem->setUsers($cache->getUsers()); + $accountsSearchItem->setUserGroups($cache->getUserGroups()); + } + + $accountsSearchItem->setTags( + $this->accountToTagRepository + ->getTagsByAccountId($accountSearchData->getId()) + ->getDataAsArray() + ); + $accountsSearchItem->setTextMaxLength($maxTextLength); + $accountsSearchItem->setColor( + $this->pickAccountColor($accountSearchData->getClientId()) + ); + $accountsSearchItem->setLink($accountLinkEnabled); + $accountsSearchItem->setFavorite( + isset($favorites[$accountSearchData->getId()]) + ); + + $accountsData[] = $accountsSearchItem; + } + + return $accountsData; + } } \ No newline at end of file diff --git a/lib/SP/Domain/Account/Services/AccountService.php b/lib/SP/Domain/Account/Services/AccountService.php index 25e539d9..09d8b9d2 100644 --- a/lib/SP/Domain/Account/Services/AccountService.php +++ b/lib/SP/Domain/Account/Services/AccountService.php @@ -164,9 +164,7 @@ final class AccountService extends Service implements AccountServiceInterface */ public function getPasswordForId(int $id): AccountPassData { - $queryFilter = $this->accountFilterUser->getFilter(); - - $result = $this->accountRepository->getPasswordForId($id, $queryFilter); + $result = $this->accountRepository->getPasswordForId($id); if ($result->getNumRows() === 0) { throw new NoSuchItemException(__u('Account not found')); @@ -418,7 +416,7 @@ final class AccountService extends Service implements AccountServiceInterface */ public function update(AccountRequest $accountRequest): void { - $this->transactionAware( + $this->accountRepository->transactionAware( function () use ($accountRequest) { $userData = $this->context->getUserData(); $userProfile = $this->context->getUserProfile() ?? new ProfileData(); @@ -535,7 +533,7 @@ final class AccountService extends Service implements AccountServiceInterface */ public function updateBulk(AccountBulkRequest $request): void { - $this->transactionAware( + $this->accountRepository->transactionAware( function () use ($request) { foreach ($request->getItemsId() as $itemId) { $accountRequest = $request->getAccountRequestForId($itemId); @@ -557,16 +555,18 @@ final class AccountService extends Service implements AccountServiceInterface */ public function editPassword(AccountRequest $accountRequest): void { - $this->transactionAware(function () use ($accountRequest) { - $this->addHistory($accountRequest->id); + $this->accountRepository->transactionAware( + function () use ($accountRequest) { + $this->addHistory($accountRequest->id); - $pass = $this->getPasswordEncrypted($accountRequest->pass); + $pass = $this->getPasswordEncrypted($accountRequest->pass); - $accountRequest->pass = $pass['pass']; - $accountRequest->key = $pass['key']; + $accountRequest->pass = $pass['pass']; + $accountRequest->key = $pass['key']; - $this->accountRepository->editPassword($accountRequest); - }); + $this->accountRepository->editPassword($accountRequest); + } + ); } /** @@ -585,14 +585,17 @@ final class AccountService extends Service implements AccountServiceInterface * @param int $accountId * * @throws \SP\Domain\Common\Services\ServiceException + * @throws \SP\Infrastructure\Common\Repositories\NoSuchItemException */ public function editRestore(int $historyId, int $accountId): void { - $this->transactionAware( + $accountHistoryData = $this->accountHistoryService->getById($historyId); + + $this->accountRepository->transactionAware( function () use ($historyId, $accountId) { $this->addHistory($accountId); - if (!$this->accountRepository->editRestore($historyId, $this->context->getUserData()->getId())) { + if (!$this->accountRepository->editRestore($accountHistoryData, $this->context->getUserData()->getId())) { throw new ServiceException(__u('Error on restoring the account')); } } @@ -604,13 +607,15 @@ final class AccountService extends Service implements AccountServiceInterface */ public function delete(int $id): AccountService { - $this->transactionAware(function () use ($id) { - $this->addHistory($id, 1); + $this->accountRepository->transactionAware( + function () use ($id) { + $this->addHistory($id, 1); - if ($this->accountRepository->delete($id) === 0) { - throw new NoSuchItemException(__u('Account not found')); + if ($this->accountRepository->delete($id) === 0) { + throw new NoSuchItemException(__u('Account not found')); + } } - }); + ); return $this; } @@ -634,18 +639,9 @@ final class AccountService extends Service implements AccountServiceInterface * @throws QueryException * @throws ConstraintException */ - public function getForUser(int $accountId = null): array + public function getForUser(?int $accountId = null): array { - $queryFilter = $this->accountFilterUser->getFilter(); - - if (null !== $accountId) { - $queryFilter->addFilter( - 'Account.id <> ? AND (Account.parentId = 0 OR Account.parentId IS NULL)', - [$accountId] - ); - } - - return $this->accountRepository->getForUser($queryFilter)->getDataAsArray(); + return $this->accountRepository->getForUser($accountId)->getDataAsArray(); } /** @@ -654,11 +650,7 @@ final class AccountService extends Service implements AccountServiceInterface */ public function getLinked(int $accountId): array { - $queryFilter = $this->accountFilterUser->getFilter(); - - $queryFilter->addFilter('Account.parentId = ?', [$accountId]); - - return $this->accountRepository->getLinked($queryFilter)->getDataAsArray(); + return $this->accountRepository->getLinked($accountId)->getDataAsArray(); } /** @@ -668,10 +660,7 @@ final class AccountService extends Service implements AccountServiceInterface */ public function getPasswordHistoryForId(int $id): AccountPassData { - $queryFilter = $this->accountFilterUser->getFilterHistory(); - $queryFilter->addFilter('AccountHistory.id = ?', [$id]); - - $result = $this->accountRepository->getPasswordHistoryForId($queryFilter); + $result = $this->accountRepository->getPasswordHistoryForId($id); if ($result->getNumRows() === 0) { throw new NoSuchItemException(__u('The account doesn\'t exist')); @@ -739,22 +728,4 @@ final class AccountService extends Service implements AccountServiceInterface { return $this->accountRepository->getAccountsPassData()->getDataAsArray(); } - - /** - * Obtener las cuentas de una búsqueda. - * - * @param \SP\Domain\Account\Services\AccountSearchFilter $accountSearchFilter - * - * @return \SP\Infrastructure\Database\QueryResult - * @throws \SP\Core\Exceptions\ConstraintException - * @throws \SP\Core\Exceptions\QueryException - * @throws \SP\Core\Exceptions\SPException - */ - public function getByFilter(AccountSearchFilter $accountSearchFilter): QueryResult - { - return $this->accountRepository->getByFilter( - $accountSearchFilter, - $this->accountFilterUser->getFilter($accountSearchFilter->getGlobalSearch()) - ); - } } \ No newline at end of file diff --git a/lib/SP/Domain/Client/Services/ClientService.php b/lib/SP/Domain/Client/Services/ClientService.php index 5d63c011..4d4ea0c4 100644 --- a/lib/SP/Domain/Client/Services/ClientService.php +++ b/lib/SP/Domain/Client/Services/ClientService.php @@ -185,6 +185,6 @@ final class ClientService extends Service implements ClientServiceInterface */ public function getAllForUser(): array { - return $this->clientRepository->getAllForFilter($this->accountFilterUser->getFilter())->getDataAsArray(); + return $this->clientRepository->getAllForFilter($this->accountFilterUser->buildFilter())->getDataAsArray(); } } \ No newline at end of file diff --git a/lib/SP/Infrastructure/Account/Repositories/AccountRepository.php b/lib/SP/Infrastructure/Account/Repositories/AccountRepository.php index 9279e5ee..c0d7159c 100644 --- a/lib/SP/Infrastructure/Account/Repositories/AccountRepository.php +++ b/lib/SP/Infrastructure/Account/Repositories/AccountRepository.php @@ -24,29 +24,25 @@ namespace SP\Infrastructure\Account\Repositories; +use Aura\SqlQuery\QueryFactory; use RuntimeException; +use SP\Core\Context\ContextInterface; +use SP\Core\Events\EventDispatcherInterface; use SP\Core\Exceptions\ConstraintException; use SP\Core\Exceptions\QueryException; use SP\Core\Exceptions\SPException; -use SP\DataModel\AccountExtData; -use SP\DataModel\AccountSearchVData; -use SP\DataModel\AccountVData; -use SP\DataModel\ItemData; +use SP\DataModel\AccountHistoryData; use SP\DataModel\ItemSearchData; use SP\Domain\Account\In\AccountRepositoryInterface; -use SP\Domain\Account\Out\AccountData; -use SP\Domain\Account\Out\AccountPassData; +use SP\Domain\Account\Services\AccountFilterUser; use SP\Domain\Account\Services\AccountPasswordRequest; use SP\Domain\Account\Services\AccountRequest; -use SP\Domain\Account\Services\AccountSearchFilter; use SP\Domain\Common\Out\SimpleModel; use SP\Infrastructure\Common\Repositories\Repository; use SP\Infrastructure\Common\Repositories\RepositoryItemTrait; +use SP\Infrastructure\Database\DatabaseInterface; use SP\Infrastructure\Database\QueryData; use SP\Infrastructure\Database\QueryResult; -use SP\Mvc\Model\QueryAssignment; -use SP\Mvc\Model\QueryCondition; -use SP\Mvc\Model\QueryJoin; /** * Class AccountRepository @@ -57,64 +53,77 @@ final class AccountRepository extends Repository implements AccountRepositoryInt { use RepositoryItemTrait; + private AccountFilterUser $accountFilterUser; + + public function __construct( + DatabaseInterface $database, + ContextInterface $session, + QueryFactory $queryFactory, + EventDispatcherInterface $eventDispatcher, + AccountFilterUser $accountFilterUser + ) { + parent::__construct($database, $session, $eventDispatcher, $queryFactory); + + $this->accountFilterUser = $accountFilterUser; + } + /** * Devolver el número total de cuentas */ public function getTotalNumAccounts(): SimpleModel { - $queryData = new QueryData(); - $queryData->setMapClassName(SimpleModel::class); - $queryData->setQuery(AccountRepositorySql::TOTAL_NUM_ACCOUNTS); + $query = $this->queryFactory + ->newSelect() + ->cols(['SUM(n) AS num']) + ->fromSubSelect('SELECT COUNT(*) AS n FROM Account UNION SELECT COUNT(*) AS n FROM AccountHistory', 'a'); - return $this->db->doSelect($queryData)->getData(); + return $this->db->doSelect(QueryData::build($query))->getData(); } /** * @param int $id - * @param QueryCondition $queryCondition * * @return QueryResult */ - public function getPasswordForId(int $id, QueryCondition $queryCondition): QueryResult + public function getPasswordForId(int $id): QueryResult { - $queryCondition->addFilter('Account.id = ?', [$id]); + $query = $this->accountFilterUser + ->buildFilter() + ->cols([ + 'Account.id,', + 'Account.name', + 'Account.login', + 'Account.pass', + 'Account.key', + 'Account.parentId', + ]) + ->where('Account.id = :id', ['id' => $id]) + ->limit(1); - $queryData = new QueryData(); - $queryData->setMapClassName(AccountPassData::class); - $queryData->setLimit(1); - $queryData->setSelect('Account.id, Account.name, Account.login, Account.pass, Account.key, Account.parentId'); - $queryData->setFrom('Account'); - $queryData->setWhere($queryCondition->getFilters()); - $queryData->setParams($queryCondition->getParams()); - - return $this->db->doSelect($queryData); + return $this->db->doSelect(QueryData::build($query)); } /** - * @param QueryCondition $queryCondition + * @param int $id * * @return QueryResult */ - public function getPasswordHistoryForId(QueryCondition $queryCondition): QueryResult + public function getPasswordHistoryForId(int $id): QueryResult { - $query = /** @lang SQL */ - 'SELECT - AccountHistory.id, - AccountHistory.name, - AccountHistory.login, - AccountHistory.pass, - AccountHistory.key, - AccountHistory.parentId, - AccountHistory.mPassHash - FROM AccountHistory - WHERE '.$queryCondition->getFilters(); + $query = $this->accountFilterUser + ->buildFilterHistory() + ->cols([ + 'AccountHistory.id,', + 'AccountHistory.name', + 'AccountHistory.login', + 'AccountHistory.pass', + 'AccountHistory.key', + 'AccountHistory.parentId', + 'AccountHistory.mPassHash', + ]) + ->where('AccountHistory.id = :id', ['id' => $id]); - $queryData = new QueryData(); - $queryData->setMapClassName(AccountPassData::class); - $queryData->setQuery($query); - $queryData->setParams($queryCondition->getParams()); - - return $this->db->doSelect($queryData); + return $this->db->doSelect(QueryData::build($query)); } /** @@ -128,11 +137,13 @@ final class AccountRepository extends Repository implements AccountRepositoryInt */ public function incrementDecryptCounter(int $id): bool { - $queryData = new QueryData(); - $queryData->setQuery(AccountRepositorySql::INCREMENT_DECRYPT_COUNTER); - $queryData->addParam($id); + $query = $this->queryFactory + ->newUpdate() + ->table('Account') + ->set('countDecrypt', '(countDecrypt + 1)') + ->where('id = :id', ['id' => $id]); - return $this->db->doQuery($queryData)->getAffectedNumRows() === 1; + return $this->db->doQuery(QueryData::build($query))->getAffectedNumRows() === 1; } /** @@ -146,26 +157,30 @@ final class AccountRepository extends Repository implements AccountRepositoryInt */ public function create($itemData): int { - $queryData = new QueryData(); - $queryData->setQuery(AccountRepositorySql::CREATE); - $queryData->setParams([ - $itemData->clientId, - $itemData->categoryId, - $itemData->name, - $itemData->login, - $itemData->url, - $itemData->pass, - $itemData->key, - $itemData->notes, - $itemData->userId, - $itemData->userGroupId, - $itemData->userId, - $itemData->isPrivate, - $itemData->isPrivateGroup, - $itemData->passDateChange, - $itemData->parentId, - ]); - $queryData->setOnErrorMessage(__u('Error while creating the account')); + $query = $this->queryFactory + ->newInsert() + ->into('Account') + ->cols([ + 'clientId' => $itemData->clientId, + 'categoryId' => $itemData->categoryId, + 'name' => $itemData->name, + 'login' => $itemData->login, + 'url' => $itemData->url, + 'pass' => $itemData->pass, + 'key' => $itemData->key, + 'notes' => $itemData->notes, + 'userId' => $itemData->userId, + 'userGroupId' => $itemData->userGroupId, + 'userEditId' => $itemData->userId, + 'isPrivate' => $itemData->isPrivate, + 'isPrivateGroup' => $itemData->isPrivateGroup, + 'passDateChange' => $itemData->passDateChange, + 'parentId' => $itemData->parentId, + ]) + ->set('dateAdd', 'NOW()') + ->set('passDate', 'UNIX_TIMESTAMP()'); + + $queryData = QueryData::build($query)->setOnErrorMessage(__u('Error while creating the account')); return $this->db->doQuery($queryData)->getLastId(); } @@ -181,16 +196,20 @@ final class AccountRepository extends Repository implements AccountRepositoryInt */ public function editPassword(AccountRequest $accountRequest): int { - $queryData = new QueryData(); - $queryData->setQuery(AccountRepositorySql::EDIT_PASSWORD); - $queryData->setParams([ - $accountRequest->pass, - $accountRequest->key, - $accountRequest->userEditId, - $accountRequest->passDateChange, - $accountRequest->id, - ]); - $queryData->setOnErrorMessage(__u('Error while updating the password')); + $query = $this->queryFactory + ->newUpdate() + ->table('Account') + ->cols([ + 'pass' => $accountRequest->pass, + 'key' => $accountRequest->key, + 'userEditId' => $accountRequest->userEditId, + 'passDateChange' => $accountRequest->passDateChange, + ]) + ->set('dateEdit', 'NOW()') + ->set('passDate', 'UNIX_TIMESTAMP()') + ->where('id = :id', ['id' => $accountRequest->id]); + + $queryData = QueryData::build($query)->setOnErrorMessage(__u('Error while updating the password')); return $this->db->doQuery($queryData)->getAffectedNumRows(); } @@ -206,10 +225,13 @@ final class AccountRepository extends Repository implements AccountRepositoryInt */ public function updatePassword(AccountPasswordRequest $request): bool { - $queryData = new QueryData(); - $queryData->setQuery(AccountRepositorySql::UPDATE_PASSWORD); - $queryData->setParams([$request->pass, $request->key, $request->id]); - $queryData->setOnErrorMessage(__u('Error while updating the password')); + $query = $this->queryFactory + ->newUpdate() + ->table('Account') + ->cols(['pass' => $request->pass, 'key' => $request->key]) + ->where('id = :id', ['id' => $request->id]); + + $queryData = QueryData::build($query)->setOnErrorMessage(__u('Error while updating the password')); return $this->db->doQuery($queryData)->getAffectedNumRows() === 1; } @@ -217,19 +239,39 @@ final class AccountRepository extends Repository implements AccountRepositoryInt /** * Restaurar una cuenta desde el histórico. * - * @param int $historyId El Id del registro en el histórico + * @param \SP\DataModel\AccountHistoryData $accountHistoryData * @param int $userId User's Id * * @return bool - * @throws ConstraintException - * @throws QueryException + * @throws \SP\Core\Exceptions\ConstraintException + * @throws \SP\Core\Exceptions\QueryException */ - public function editRestore(int $historyId, int $userId): bool + public function editRestore(AccountHistoryData $accountHistoryData, int $userId): bool { - $queryData = new QueryData(); - $queryData->setQuery(AccountRepositorySql::EDIT_RESTORE); - $queryData->setParams([$historyId, $userId]); - $queryData->setOnErrorMessage(__u('Error on restoring the account')); + $query = $this->queryFactory + ->newUpdate() + ->table('Account') + ->cols([ + 'clientId' => $accountHistoryData->getClientId(), + 'categoryId' => $accountHistoryData->getCategoryId(), + 'name' => $accountHistoryData->getName(), + 'login' => $accountHistoryData->getLogin(), + 'url' => $accountHistoryData->getUrl(), + 'notes' => $accountHistoryData->getNotes(), + 'userGroupId' => $accountHistoryData->getUserGroupId(), + 'userEditId' => $userId, + 'pass' => $accountHistoryData->getPass(), + 'key' => $accountHistoryData->getKey(), + 'passDate' => $accountHistoryData->getPassDate(), + 'passDateChange' => $accountHistoryData->getPassDateChange(), + 'parentId' => $accountHistoryData->getParentId(), + 'isPrivate' => $accountHistoryData->getIsPrivate(), + 'isPrivateGroup' => $accountHistoryData->getIsPrivateGroup(), + ]) + ->set('dateEdit', 'NOW()') + ->where('id = :id', ['id' => $accountHistoryData->getAccountId()]); + + $queryData = QueryData::build($query)->setOnErrorMessage(__u('Error on restoring the account')); return $this->db->doQuery($queryData)->getAffectedNumRows() === 1; } @@ -245,10 +287,12 @@ final class AccountRepository extends Repository implements AccountRepositoryInt */ public function delete(int $id): int { - $queryData = new QueryData(); - $queryData->setQuery(AccountRepositorySql::DELETE); - $queryData->addParam($id); - $queryData->setOnErrorMessage(__u('Error while deleting the account')); + $query = $this->queryFactory + ->newDelete() + ->from('Account') + ->where('id = :id', ['id' => $id]); + + $queryData = QueryData::build($query)->setOnErrorMessage(__u('Error while deleting the account')); return $this->db->doQuery($queryData)->getAffectedNumRows(); } @@ -263,53 +307,34 @@ final class AccountRepository extends Repository implements AccountRepositoryInt */ public function update($itemData): int { - $queryAssignment = new QueryAssignment(); - - $queryAssignment->setFields([ - 'clientId', - 'categoryId', - 'name', - 'login', - 'url', - 'notes', - 'userEditId', - 'dateEdit = NOW()', - 'passDateChange', - 'isPrivate', - 'isPrivateGroup', - 'parentId', - ], [ - $itemData->clientId, - $itemData->categoryId, - $itemData->name, - $itemData->login, - $itemData->url, - $itemData->notes, - $itemData->userEditId, - $itemData->passDateChange, - $itemData->isPrivate, - $itemData->isPrivateGroup, - $itemData->parentId, - ]); - - - $queryData = new QueryData(); + $query = $this->queryFactory + ->newUpdate() + ->table('Account') + ->where('id = :id', ['id' => $itemData->id]) + ->cols([ + 'clientId' => $itemData->clientId, + 'categoryId' => $itemData->categoryId, + 'name' => $itemData->name, + 'login' => $itemData->login, + 'url' => $itemData->url, + 'notes' => $itemData->notes, + 'userEditId' => $itemData->userEditId, + 'passDateChange' => $itemData->passDateChange, + 'isPrivate' => $itemData->isPrivate, + 'isPrivateGroup' => $itemData->isPrivateGroup, + 'parentId' => $itemData->parentId, + ]) + ->set('dateEdit', 'NOW()'); if ($itemData->changeUserGroup) { - $queryAssignment->addField('userGroupId', $itemData->userGroupId); + $query->col('userGroupId', $itemData->userGroupId); } if ($itemData->changeOwner) { - $queryAssignment->addField('userId', $itemData->userId); + $query->col('userId', $itemData->userId); } - $query = /** @lang SQL */ - 'UPDATE Account SET '.$queryAssignment->getAssignments().' WHERE id = ?'; - - $queryData->setQuery($query); - $queryData->setParams($queryAssignment->getValues()); - $queryData->addParam($itemData->id); - $queryData->setOnErrorMessage(__u('Error while updating the account')); + $queryData = QueryData::build($query)->setOnErrorMessage(__u('Error while updating the account')); return $this->db->doQuery($queryData)->getAffectedNumRows(); } @@ -324,16 +349,14 @@ final class AccountRepository extends Repository implements AccountRepositoryInt */ public function updateBulk(AccountRequest $itemData): int { - $queryAssignment = new QueryAssignment(); - - $queryAssignment->setFields([ - 'userEditId', - 'dateEdit = NOW()', - ], [ - $itemData->userEditId, - ]); - - $queryData = new QueryData(); + $query = $this->queryFactory + ->newUpdate() + ->table('Account') + ->where('id = :id', ['id' => $itemData->id]) + ->cols([ + 'userEditId' => $itemData->userEditId, + ]) + ->set('dateEdit', 'NOW()'); $optional = ['clientId', 'categoryId', 'userId', 'userGroupId', 'passDateChange']; @@ -341,7 +364,7 @@ final class AccountRepository extends Repository implements AccountRepositoryInt foreach ($optional as $field) { if (isset($itemData->{$field}) && !empty($itemData->{$field})) { - $queryAssignment->addField($field, $itemData->{$field}); + $query->col($field, $itemData->{$field}); $optionalCount++; } else { logger(sprintf('Field \'%s\' not found in $itemData', $field), 'ERROR'); @@ -352,13 +375,7 @@ final class AccountRepository extends Repository implements AccountRepositoryInt return 0; } - $query = /** @lang SQL */ - 'UPDATE Account SET '.$queryAssignment->getAssignments().' WHERE id = ?'; - - $queryData->setQuery($query); - $queryData->setParams($queryAssignment->getValues()); - $queryData->addParam($itemData->id); - $queryData->setOnErrorMessage(__u('Error while updating the account')); + $queryData = QueryData::build($query)->setOnErrorMessage(__u('Error while updating the account')); return $this->db->doQuery($queryData)->getAffectedNumRows(); } @@ -372,11 +389,13 @@ final class AccountRepository extends Repository implements AccountRepositoryInt */ public function getById(int $id): QueryResult { - $queryData = new QueryData(); - $queryData->setQuery(AccountRepositorySql::EDIT_BY_ID); - $queryData->setMapClassName(AccountVData::class); - $queryData->addParam($id); - $queryData->setOnErrorMessage(__u('Error while retrieving account\'s data')); + $query = $this->queryFactory + ->newSelect() + ->from('account_data_v') + ->where('id = :id', ['id' => $id]) + ->limit(1); + + $queryData = QueryData::build($query)->setOnErrorMessage(__u('Error while retrieving account\'s data')); return $this->db->doSelect($queryData); } @@ -388,11 +407,9 @@ final class AccountRepository extends Repository implements AccountRepositoryInt */ public function getAll(): QueryResult { - $queryData = new QueryData(); - $queryData->setMapClassName(AccountData::class); - $queryData->setQuery(AccountRepositorySql::GET_ALL); + $query = $this->queryFactory->newSelect()->from('Account'); - return $this->db->doSelect($queryData); + return $this->db->doSelect(QueryData::build($query)); } /** @@ -420,11 +437,11 @@ final class AccountRepository extends Repository implements AccountRepositoryInt return 0; } - $queryData = new QueryData(); - - $queryData->setQuery('DELETE FROM Account WHERE id IN ('.$this->getParamsFromArray($ids).')'); - $queryData->setParams($ids); - $queryData->setOnErrorMessage(__u('Error while deleting the accounts')); + $query = $this->queryFactory + ->newDelete() + ->from('Account') + ->where('id IN (:id)', $ids); + $queryData = QueryData::build($query)->setOnErrorMessage(__u('Error while deleting the accounts')); return $this->db->doQuery($queryData)->getAffectedNumRows(); } @@ -468,34 +485,41 @@ final class AccountRepository extends Repository implements AccountRepositoryInt */ public function search(ItemSearchData $itemSearchData): QueryResult { - $queryData = new QueryData(); - $queryData->setSelect('id, name, clientName, categoryName, userName, userGroupName'); - $queryData->setFrom('account_search_v'); - $queryData->setOrder('name, clientName'); + $query = $this->queryFactory + ->newSelect() + ->from('account_search_v') + ->cols([ + 'id', + 'name', + 'clientName', + 'categoryName', + 'userName', + 'userGroupName', + + ]) + ->orderBy(['name ASC', 'clientName ASC']) + ->limit($itemSearchData->getLimitCount()) + ->offset($itemSearchData->getLimitStart()); if (!empty($itemSearchData->getSeachString())) { - $queryData->setWhere( - 'name LIKE ? - OR clientName LIKE ? - OR categoryName LIKE ? - OR userName LIKE ? - OR userGroupName LIKE ?' - ); + $query->where('name LIKE :name') + ->orWhere('clientName LIKE :clientName') + ->orWhere('categoryName LIKE :categoryName') + ->orWhere('userName LIKE :userName') + ->orWhere('userGroupName LIKE :userGroupName'); $search = '%'.$itemSearchData->getSeachString().'%'; - $queryData->addParam($search); - $queryData->addParam($search); - $queryData->addParam($search); - $queryData->addParam($search); - $queryData->addParam($search); + + $query->bindValues([ + 'name' => $search, + 'clientName' => $search, + 'categoryName' => $search, + 'userName' => $search, + 'userGroupName' => $search, + ]); } - $queryData->setLimit( - '?,?', - [$itemSearchData->getLimitStart(), $itemSearchData->getLimitCount()] - ); - - return $this->db->doSelect($queryData, true); + return $this->db->doSelect(QueryData::build($query), true); } /** @@ -509,11 +533,13 @@ final class AccountRepository extends Repository implements AccountRepositoryInt */ public function incrementViewCounter(int $id): bool { - $queryData = new QueryData(); - $queryData->setQuery(AccountRepositorySql::INCREMENT_VIEW_COUNTER); - $queryData->addParam($id); + $query = $this->queryFactory + ->newUpdate() + ->table('Account') + ->set('countView', '(countView + 1)') + ->where('id = :id', ['id' => $id]); - return $this->db->doQuery($queryData)->getAffectedNumRows() === 1; + return $this->db->doQuery(QueryData::build($query))->getAffectedNumRows() === 1; } /** @@ -525,164 +551,76 @@ final class AccountRepository extends Repository implements AccountRepositoryInt */ public function getDataForLink(int $id): QueryResult { - $queryData = new QueryData(); - $queryData->setQuery(AccountRepositorySql::GET_DATA_FOR_LINK); - $queryData->setMapClassName(AccountExtData::class); - $queryData->addParam($id); - $queryData->setOnErrorMessage(__u('Error while retrieving account\'s data')); + $query = $this->queryFactory + ->newSelect() + ->from('Account') + ->join('INNER', 'Client', 'Account.clientId = Client.id') + ->join('INNER', 'Category', 'Account.categoryId = Category.id') + ->cols([ + 'Account.name', + 'Account.login', + 'Account.pass', + 'Account.key', + 'Account.url', + 'Account.notes', + 'Client.name AS clientName', + 'Category.name AS categoryName', + ]) + ->where('Account.id = :id', ['id' => $id]); + + $queryData = QueryData::build($query)->setOnErrorMessage(__u('Error while retrieving account\'s data')); return $this->db->doSelect($queryData); } /** - * Obtener las cuentas de una búsqueda. - * - * @param AccountSearchFilter $accountSearchFilter - * @param QueryCondition $queryFilterUser + * @param int|null $accountId * * @return QueryResult */ - public function getByFilter( - AccountSearchFilter $accountSearchFilter, - QueryCondition $queryFilterUser - ): QueryResult { - $queryFilters = new QueryCondition(); - - // Sets the search text depending on if special search filters are being used - $searchText = $accountSearchFilter->getCleanTxtSearch(); - - if (!empty($searchText)) { - $queryFilters->addFilter( - 'Account.name LIKE ? OR Account.login LIKE ? OR Account.url LIKE ? OR Account.notes LIKE ?', - array_fill(0, 4, '%'.$searchText.'%') - ); - } - - // Gets special search filters - $stringFilters = $accountSearchFilter->getStringFilters(); - - if ($stringFilters->hasFilters()) { - $queryFilters->addFilter( - $stringFilters->getFilters($accountSearchFilter->getFilterOperator()), - $stringFilters->getParams() - ); - } - - if ($accountSearchFilter->getCategoryId() !== null) { - $queryFilters->addFilter( - 'Account.categoryId = ?', - [$accountSearchFilter->getCategoryId()] - ); - } - - if ($accountSearchFilter->getClientId() !== null) { - $queryFilters->addFilter( - 'Account.clientId = ?', - [$accountSearchFilter->getClientId()] - ); - } - - $where = []; - - if ($queryFilterUser->hasFilters()) { - $where[] = $queryFilterUser->getFilters(); - } - - $queryData = new QueryData(); - $queryJoins = new QueryJoin(); - - if ($accountSearchFilter->isSearchFavorites() === true) { - $queryJoins->addJoin( - 'INNER JOIN AccountToFavorite ON (AccountToFavorite.accountId = Account.id AND AccountToFavorite.userId = ?)', - [$this->context->getUserData()->getId()] - ); - } - - if ($accountSearchFilter->hasTags()) { - $queryJoins->addJoin('INNER JOIN AccountToTag ON AccountToTag.accountId = Account.id'); - $queryFilters->addFilter( - 'AccountToTag.tagId IN ('.$this->getParamsFromArray($accountSearchFilter->getTagsId()).')', - $accountSearchFilter->getTagsId() - ); - - if (QueryCondition::CONDITION_AND === $accountSearchFilter->getFilterOperator()) { - $groupBy = sprintf( - 'Account.id HAVING COUNT(DISTINCT AccountToTag.tagId) = %d', - count($accountSearchFilter->getTagsId()) - ); - - $queryData->setGroupBy($groupBy); - } - } - - if ($queryFilters->hasFilters()) { - $where[] = $queryFilters->getFilters($accountSearchFilter->getFilterOperator()); - } - - $queryData->setWhere($where); - $queryData->setParams( - array_merge( - $queryJoins->getParams(), - $queryFilterUser->getParams(), - $queryFilters->getParams() + public function getForUser(?int $accountId = null): QueryResult + { + $query = $this->accountFilterUser + ->buildFilter() + ->cols( + [ + 'Account.id', + 'Account.name', + 'C.name AS clientName', + ] ) - ); - $queryData->setSelect('DISTINCT Account.*'); - $queryData->setFrom('account_search_v Account '.$queryJoins->getJoins()); - $queryData->setOrder($accountSearchFilter->getOrderString()); + ->join('LEFT', 'Client AS C', 'Account.clientId = C.id') + ->orderBy(['Account.name ASC']); - if ($accountSearchFilter->getLimitCount() > 0) { - $queryLimit = '?, ?'; - - $queryData->addParam($accountSearchFilter->getLimitStart()); - $queryData->addParam($accountSearchFilter->getLimitCount()); - $queryData->setLimit($queryLimit); + if ($accountId) { + $query->where('Account.id <> :id', ['id' => $accountId]); + $query->where('Account.parentId = 0 OR Account.parentId IS NULL'); } - $queryData->setMapClassName(AccountSearchVData::class); - - return $this->db->doSelect($queryData, true); + return $this->db->doSelect(QueryData::build($query)); } /** - * @param QueryCondition $queryFilter + * @param int $accountId * * @return QueryResult */ - public function getForUser(QueryCondition $queryFilter): QueryResult + public function getLinked(int $accountId): QueryResult { - $query = /** @lang SQL */ - 'SELECT Account.id, Account.name, C.name AS clientName - FROM Account - LEFT JOIN Client C ON Account.clientId = C.id - WHERE '.$queryFilter->getFilters().' ORDER BY name'; + $query = $this->accountFilterUser + ->buildFilter() + ->cols( + [ + 'Account.id', + 'Account.name', + 'Client.name AS clientName', + ] + ) + ->join('INNER', 'Client', 'Account.clientId = Client.id') + ->where('Account.parentId = :parentId', ['parentId' => $accountId]) + ->orderBy(['Account.name ASC']); - $queryData = new QueryData(); - $queryData->setMapClassName(ItemData::class); - $queryData->setQuery($query); - $queryData->setParams($queryFilter->getParams()); - - return $this->db->doSelect($queryData); - } - - /** - * @param QueryCondition $queryFilter - * - * @return QueryResult - */ - public function getLinked(QueryCondition $queryFilter): QueryResult - { - $query = /** @lang SQL */ - 'SELECT Account.id, Account.name, Client.name AS clientName - FROM Account - INNER JOIN Client ON Account.clientId = Client.id - WHERE '.$queryFilter->getFilters().' ORDER BY Account.name'; - - $queryData = new QueryData(); - $queryData->setQuery($query); - $queryData->setParams($queryFilter->getParams()); - - return $this->db->doSelect($queryData); + return $this->db->doSelect(QueryData::build($query)); } /** @@ -692,9 +630,19 @@ final class AccountRepository extends Repository implements AccountRepositoryInt */ public function getAccountsPassData(): QueryResult { - $queryData = new QueryData(); - $queryData->setQuery(AccountRepositorySql::GET_ACCOUNT_PASS_DATA); + $query = $this->queryFactory + ->newSelect() + ->from('Account') + ->cols( + [ + 'id', + 'name', + 'pass', + 'key', + ] + ) + ->where('BIT_LENGTH(pass) > 0'); - return $this->db->doSelect($queryData); + return $this->db->doSelect(QueryData::build($query)); } } \ No newline at end of file diff --git a/lib/SP/Infrastructure/Account/Repositories/AccountRepositorySql.php b/lib/SP/Infrastructure/Account/Repositories/AccountRepositorySql.php deleted file mode 100644 index 3f301d39..00000000 --- a/lib/SP/Infrastructure/Account/Repositories/AccountRepositorySql.php +++ /dev/null @@ -1,114 +0,0 @@ -. - */ - -namespace SP\Infrastructure\Account\Repositories; - - -/** - * Class AccountRepositorySql - */ -final class AccountRepositorySql -{ - public const TOTAL_NUM_ACCOUNTS = 'SELECT SUM(n) AS num FROM - (SELECT COUNT(*) AS n FROM Account UNION SELECT COUNT(*) AS n FROM AccountHistory) a'; - - public const INCREMENT_DECRYPT_COUNTER = 'UPDATE Account SET countDecrypt = (countDecrypt + 1) WHERE id = ? LIMIT 1'; - - public const CREATE = 'INSERT INTO Account SET - clientId = ?, - categoryId = ?, - `name` = ?, - login = ?, - url = ?, - pass = ?, - `key` = ?, - notes = ?, - dateAdd = NOW(), - userId = ?, - userGroupId = ?, - userEditId = ?, - isPrivate = ?, - isPrivateGroup = ?, - passDate = UNIX_TIMESTAMP(), - passDateChange = ?, - parentId = ?'; - - public const EDIT_PASSWORD = 'UPDATE Account SET - pass = ?, - `key` = ?, - userEditId = ?, - dateEdit = NOW(), - passDate = UNIX_TIMESTAMP(), - passDateChange = ? - WHERE id = ?'; - - public const UPDATE_PASSWORD = 'UPDATE Account SET - pass = ?, - `key` = ? - WHERE id = ?'; - - public const EDIT_RESTORE = 'UPDATE Account dst, - (SELECT * FROM AccountHistory AH WHERE AH.id = ?) src SET - dst.clientId = src.clientId, - dst.categoryId = src.categoryId, - dst.name = src.name, - dst.login = src.login, - dst.url = src.url, - dst.notes = src.notes, - dst.userGroupId = src.userGroupId, - dst.userEditId = ?, - dst.dateEdit = NOW(), - dst.pass = src.pass, - dst.key = src.key, - dst.passDate = src.passDate, - dst.passDateChange = src.passDateChange, - dst.parentId = src.parentId, - dst.isPrivate = src.isPrivate, - dst.isPrivateGroup = src.isPrivateGroup - WHERE dst.id = src.accountId'; - - public const DELETE = 'DELETE FROM Account WHERE id = ? LIMIT 1'; - - public const EDIT_BY_ID = 'SELECT * FROM account_data_v WHERE id = ? LIMIT 1'; - - public const GET_ALL = 'SELECT * FROM Account ORDER BY id'; - - public const INCREMENT_VIEW_COUNTER = 'UPDATE Account SET countView = (countView + 1) WHERE id = ? LIMIT 1'; - - public const GET_DATA_FOR_LINK = 'SELECT Account.id, - Account.name, - Account.login, - Account.pass, - Account.key, - Account.url, - Account.notes, - Client.name AS clientName, - Category.name AS categoryName - FROM Account - INNER JOIN Client ON Account.clientId = Client.id - INNER JOIN Category ON Account.categoryId = Category.id - WHERE Account.id = ? LIMIT 1'; - - public const GET_ACCOUNT_PASS_DATA = 'SELECT id, `name`, pass, `key` FROM Account WHERE BIT_LENGTH(pass) > 0'; -} \ No newline at end of file diff --git a/lib/SP/Infrastructure/Account/Repositories/AccountSearchRepository.php b/lib/SP/Infrastructure/Account/Repositories/AccountSearchRepository.php new file mode 100644 index 00000000..b90e59e8 --- /dev/null +++ b/lib/SP/Infrastructure/Account/Repositories/AccountSearchRepository.php @@ -0,0 +1,391 @@ +. + */ + +namespace SP\Infrastructure\Account\Repositories; + + +use Aura\SqlQuery\Common\SelectInterface; +use Aura\SqlQuery\QueryFactory; +use SP\Core\Context\ContextInterface; +use SP\Core\Events\EventDispatcherInterface; +use SP\DataModel\AccountSearchVData; +use SP\Domain\Account\Search\AccountSearchConstants; +use SP\Domain\Account\Search\AccountSearchFilter; +use SP\Domain\Account\Services\AccountFilterUser; +use SP\Infrastructure\Common\Repositories\Repository; +use SP\Infrastructure\Database\DatabaseInterface; +use SP\Infrastructure\Database\QueryData; +use SP\Infrastructure\Database\QueryResult; +use SP\Util\Filter; + +/** + * Class AccountSearchRepository + */ +final class AccountSearchRepository extends Repository implements AccountSearchRepositoryInterface +{ + protected SelectInterface $query; + private AccountFilterUser $accountFilterUser; + + public function __construct( + DatabaseInterface $database, + ContextInterface $session, + EventDispatcherInterface $eventDispatcher, + QueryFactory $queryFactory, + AccountFilterUser $accountFilterUser + ) { + parent::__construct($database, $session, $eventDispatcher, $queryFactory); + + $this->accountFilterUser = $accountFilterUser; + } + + /** + * Obtener las cuentas de una búsqueda. + * + * @param AccountSearchFilter $accountSearchFilter + * + * @return QueryResult + */ + public function getByFilter(AccountSearchFilter $accountSearchFilter): QueryResult + { + $this->accountFilterUser->buildFilter($accountSearchFilter->getGlobalSearch(), $this->query); + + // Sets the search text depending on whether special search filters are being used + $searchText = $accountSearchFilter->getCleanTxtSearch(); + + if (!empty($searchText)) { + $searchTextLike = '%'.$searchText.'%'; + + $this->query + ->where( + '(Account.name LIKE :name OR Account.login LIKE :login OR Account.url LIKE :url OR Account.notes LIKE :notes)', + [ + 'name' => $searchTextLike, + 'login' => $searchTextLike, + 'url' => $searchTextLike, + 'notes' => $searchTextLike, + ] + ); + } + + if ($accountSearchFilter->getCategoryId() !== null) { + $this->query + ->where( + 'Account.categoryId = :categoryId', + [ + 'categoryId' => $accountSearchFilter->getCategoryId(), + ] + ); + } + + if ($accountSearchFilter->getClientId() !== null) { + $this->query + ->where( + 'Account.categoryId = :clientId', + [ + 'categoryId' => $accountSearchFilter->getClientId(), + ] + ); + } + + if ($accountSearchFilter->isSearchFavorites() === true) { + $this->query + ->join( + 'INNER', + 'AccountToFavorite', + 'AccountToFavorite.accountId = Account.id AND AccountToFavorite.userId = :userId', + [ + 'userId' => $this->context->getUserData()->getId(), + ] + ); + } + + if ($accountSearchFilter->hasTags()) { + $this->query->join( + 'INNER', + 'AccountToTag', + 'AccountToTag.accountId = Account.id' + ); + + $this->query + ->where( + 'AccountToTag.tagId IN (:tagId)', + [ + 'tagId' => $accountSearchFilter->getTagsId(), + ] + ); + + if (AccountSearchConstants::FILTER_CHAIN_AND === $accountSearchFilter->getFilterOperator()) { + $this->query + ->groupBy(['Account.id']) + ->having( + 'COUNT(DISTINCT AccountToTag.tagId) = :tagsCount', + [ + 'tagsCount' => count($accountSearchFilter->getTagsId()), + ] + ); + } + } + + $this->setOrder($accountSearchFilter); + + if ($accountSearchFilter->getLimitCount() > 0) { + $this->query->limit($accountSearchFilter->getLimitCount()); + $this->query->offset($accountSearchFilter->getLimitStart()); + } + + return $this->db->doSelect( + QueryData::build($this->query)->setMapClassName(AccountSearchVData::class), + true + ); + } + + /** + * Devuelve la cadena de ordenación de la consulta + */ + private function setOrder(AccountSearchFilter $filter): void + { + $orderKey = match ($filter->getSortKey()) { + AccountSearchConstants::SORT_NAME => 'Account.name', + AccountSearchConstants::SORT_CATEGORY => 'Account.categoryName', + AccountSearchConstants::SORT_LOGIN => 'Account.login', + AccountSearchConstants::SORT_URL => 'Account.url', + AccountSearchConstants::SORT_CLIENT => 'Account.clientName', + default => 'Account.clientName, Account.name', + }; + + if ($filter->isSortViews() && !$filter->getSortKey()) { + $this->query->orderBy(['Account.countView DESC']); + } else { + $sortOrder = match ($filter->getSortOrder()) { + AccountSearchConstants::SORT_DIR_ASC => 'ASC', + AccountSearchConstants::SORT_DIR_DESC => 'DESC', + }; + + $this->query->orderBy([ + sprintf('%s %s', $orderKey, $sortOrder), + ]); + } + } + + /** + * @param int $userId + * @param int $userGroupId + * + * @return \Aura\SqlQuery\Common\SelectInterface + */ + public function withFilterForUser(int $userId, int $userGroupId): SelectInterface + { + $where = [ + 'Account.userId = :userId', + 'Account.userGroupId = :userGroupId', + 'Account.id IN (SELECT AccountToUser.accountId FROM AccountToUser WHERE AccountToUser.accountId = Account.id AND AccountToUser.userId = :userId + UNION + SELECT AccountToUserGroup.accountId FROM AccountToUserGroup WHERE AccountToUserGroup.accountId = Account.id AND AccountToUserGroup.userGroupId = :userGroupId)', + ]; + + return $this->query + ->where(sprintf('(%s)', join(sprintf(' %s ', AccountSearchConstants::FILTER_CHAIN_OR), $where))) + ->bindValues([ + 'userId' => $userId, + 'userGroupId' => $userGroupId, + ]); + } + + /** + * @param int $userGroupId + * + * @return \Aura\SqlQuery\Common\SelectInterface + */ + public function withFilterForGroup(int $userGroupId): SelectInterface + { + return $this->query + ->where('Account.userGroupId = :userGroupId') + ->orWhere( + '(Account.id IN (SELECT AccountToUserGroup.accountId FROM AccountToUserGroup WHERE AccountToUserGroup.accountId = id AND AccountToUserGroup.userGroupId = :userGroupId))' + ) + ->bindValues([ + 'userGroupId' => $userGroupId, + ]); + + } + + /** + * @param string $userGroupName + * + * @return \Aura\SqlQuery\Common\SelectInterface + */ + public function withFilterForMainGroup(string $userGroupName): SelectInterface + { + $userGroupNameLike = '%'.Filter::safeSearchString($userGroupName).'%'; + + return $this->query + ->where('Account.userGroupName LIKE :userGroupName') + ->bindValues([ + 'userGroupName' => $userGroupNameLike, + ]); + } + + /** + * @param string $owner + * + * @return \Aura\SqlQuery\Common\SelectInterface + */ + public function withFilterForOwner(string $owner): SelectInterface + { + $ownerLike = '%'.Filter::safeSearchString($owner).'%'; + + return $this->query + ->where('(Account.userLogin LIKE :userLogin OR Account.userName LIKE :userName)') + ->bindValues([ + 'userLogin' => $ownerLike, + 'userName' => $ownerLike, + ]); + } + + /** + * @param string $fileName + * + * @return \Aura\SqlQuery\Common\SelectInterface + */ + public function withFilterForFile(string $fileName): SelectInterface + { + $fileNameLike = '%'.Filter::safeSearchString($fileName).'%'; + + return $this->query + ->where( + '(Account.id IN (SELECT AccountFile.accountId FROM AccountFile WHERE AccountFile.name LIKE :fileName))' + ) + ->bindValues([ + 'fileName' => $fileNameLike, + ]); + } + + /** + * @param int $accountId + * + * @return \Aura\SqlQuery\Common\SelectInterface + */ + public function withFilterForAccountId(int $accountId): SelectInterface + { + return $this->query + ->where('Account.id = :id') + ->bindValues([ + 'id' => $accountId, + ]); + } + + /** + * @param string $clientName + * + * @return \Aura\SqlQuery\Common\SelectInterface + */ + public function withFilterForClient(string $clientName): SelectInterface + { + $clientNameLike = '%'.Filter::safeSearchString($clientName).'%'; + + return $this->query + ->where('Account.clientName LIKE :clientName') + ->bindValues([ + 'clientName' => $clientNameLike, + ]); + } + + /** + * @param string $categoryName + * + * @return \Aura\SqlQuery\Common\SelectInterface + */ + public function withFilterForCategory(string $categoryName): SelectInterface + { + $categoryNameLike = '%'.Filter::safeSearchString($categoryName).'%'; + + return $this->query + ->where('Account.categoryName LIKE :categoryName') + ->bindValues([ + 'categoryName' => $categoryNameLike, + ]); + } + + /** + * @param string $accountName + * + * @return \Aura\SqlQuery\Common\SelectInterface + */ + public function withFilterForAccountNameRegex(string $accountName): SelectInterface + { + return $this->query + ->where('Account.name REGEXP :name') + ->bindValues([ + 'name' => $accountName, + ]); + } + + public function withFilterForIsExpired(): SelectInterface + { + return $this->query + ->where('(Account.passDateChange > 0 AND UNIX_TIMESTAMP() > Account.passDateChange)'); + } + + public function withFilterForIsNotExpired(): SelectInterface + { + return $this->query + ->where( + '(Account.passDateChange = 0 OR Account.passDateChange IS NULL OR UNIX_TIMESTAMP() < Account.passDateChange)' + ); + } + + /** + * @param int $userId + * @param int $userGroupId + * + * @return \Aura\SqlQuery\Common\SelectInterface + */ + public function withFilterForIsPrivate(int $userId, int $userGroupId): SelectInterface + { + return $this->query + ->where( + '(Account.isPrivate = 1 AND Account.userId = :userId) OR (Account.isPrivateGroup = 1 AND Account.userGroupId = :userGroupId)' + ) + ->bindValues([ + 'userId' => $userId, + 'userGroupId' => $userGroupId, + ]); + } + + public function withFilterForIsNotPrivate(): SelectInterface + { + return $this->query + ->where( + '(Account.isPrivate = 0 OR Account.isPrivate IS NULL) AND (Account.isPrivateGroup = 0 OR Account.isPrivateGroup IS NULL)' + ); + } + + protected function initialize() + { + $this->query = $this->queryFactory + ->newSelect() + ->from('account_search_v AS Account') + ->distinct(); + } +} \ No newline at end of file diff --git a/lib/SP/Infrastructure/Account/Repositories/AccountSearchRepositoryInterface.php b/lib/SP/Infrastructure/Account/Repositories/AccountSearchRepositoryInterface.php new file mode 100644 index 00000000..829827fa --- /dev/null +++ b/lib/SP/Infrastructure/Account/Repositories/AccountSearchRepositoryInterface.php @@ -0,0 +1,123 @@ +. + */ + +namespace SP\Infrastructure\Account\Repositories; + + +use Aura\SqlQuery\Common\SelectInterface; +use SP\Domain\Account\Search\AccountSearchFilter; +use SP\Infrastructure\Database\QueryResult; + +/** + * Class AccountSearchRepository + */ +interface AccountSearchRepositoryInterface +{ + /** + * Obtener las cuentas de una búsqueda. + * + * @param AccountSearchFilter $accountSearchFilter + * + * @return QueryResult + */ + public function getByFilter(AccountSearchFilter $accountSearchFilter): QueryResult; + + /** + * @param int $userId + * @param int $userGroupId + * + * @return \Aura\SqlQuery\Common\SelectInterface + */ + public function withFilterForUser(int $userId, int $userGroupId): SelectInterface; + + /** + * @param int $userGroupId + * + * @return \Aura\SqlQuery\Common\SelectInterface + */ + public function withFilterForGroup(int $userGroupId): SelectInterface; + + /** + * @param string $userGroupName + * + * @return \Aura\SqlQuery\Common\SelectInterface + */ + public function withFilterForMainGroup(string $userGroupName): SelectInterface; + + /** + * @param string $owner + * + * @return \Aura\SqlQuery\Common\SelectInterface + */ + public function withFilterForOwner(string $owner): SelectInterface; + + /** + * @param string $fileName + * + * @return \Aura\SqlQuery\Common\SelectInterface + */ + public function withFilterForFile(string $fileName): SelectInterface; + + /** + * @param int $accountId + * + * @return \Aura\SqlQuery\Common\SelectInterface + */ + public function withFilterForAccountId(int $accountId): SelectInterface; + + /** + * @param string $clientName + * + * @return \Aura\SqlQuery\Common\SelectInterface + */ + public function withFilterForClient(string $clientName): SelectInterface; + + /** + * @param string $categoryName + * + * @return \Aura\SqlQuery\Common\SelectInterface + */ + public function withFilterForCategory(string $categoryName): SelectInterface; + + /** + * @param string $accountName + * + * @return \Aura\SqlQuery\Common\SelectInterface + */ + public function withFilterForAccountNameRegex(string $accountName): SelectInterface; + + public function withFilterForIsExpired(): SelectInterface; + + public function withFilterForIsNotExpired(): SelectInterface; + + /** + * @param int $userId + * @param int $userGroupId + * + * @return \Aura\SqlQuery\Common\SelectInterface + */ + public function withFilterForIsPrivate(int $userId, int $userGroupId): SelectInterface; + + public function withFilterForIsNotPrivate(): SelectInterface; +} \ No newline at end of file diff --git a/lib/SP/Infrastructure/Common/Repositories/Repository.php b/lib/SP/Infrastructure/Common/Repositories/Repository.php index 21a769cc..ece09840 100644 --- a/lib/SP/Infrastructure/Common/Repositories/Repository.php +++ b/lib/SP/Infrastructure/Common/Repositories/Repository.php @@ -24,7 +24,14 @@ namespace SP\Infrastructure\Common\Repositories; +use Aura\SqlQuery\QueryFactory; +use Closure; +use Exception; use SP\Core\Context\ContextInterface; +use SP\Core\Events\Event; +use SP\Core\Events\EventDispatcherInterface; +use SP\Core\Events\EventMessage; +use SP\Domain\Common\Services\ServiceException; use SP\Infrastructure\Database\DatabaseInterface; /** @@ -34,16 +41,59 @@ use SP\Infrastructure\Database\DatabaseInterface; */ abstract class Repository { - protected ContextInterface $context; - protected DatabaseInterface $db; + protected ContextInterface $context; + protected DatabaseInterface $db; + protected QueryFactory $queryFactory; + protected EventDispatcherInterface $eventDispatcher; - final public function __construct(DatabaseInterface $database, ContextInterface $session) - { + public function __construct( + DatabaseInterface $database, + ContextInterface $session, + EventDispatcherInterface $eventDispatcher, + QueryFactory $queryFactory + ) { $this->db = $database; $this->context = $session; + $this->queryFactory = $queryFactory; + $this->eventDispatcher = $eventDispatcher; if (method_exists($this, 'initialize')) { $this->initialize(); } } + + /** + * Bubbles a Closure in a database transaction + * + * @param \Closure $closure + * + * @return mixed + * @throws \SP\Domain\Common\Services\ServiceException + * @throws \Exception + */ + final public function transactionAware(Closure $closure) + { + if ($this->db->beginTransaction()) { + try { + $result = $closure->call($this); + + $this->db->endTransaction(); + + return $result; + } catch (Exception $e) { + $this->db->rollbackTransaction(); + + logger('Transaction:Rollback'); + + $this->eventDispatcher->notifyEvent( + 'database.rollback', + new Event($this, EventMessage::factory()->addDescription(__u('Rollback'))) + ); + + throw $e; + } + } else { + throw new ServiceException(__u('Unable to start a transaction')); + } + } } \ No newline at end of file diff --git a/lib/SP/Infrastructure/Database/Database.php b/lib/SP/Infrastructure/Database/Database.php index eb2e837f..e54977cf 100644 --- a/lib/SP/Infrastructure/Database/Database.php +++ b/lib/SP/Infrastructure/Database/Database.php @@ -24,6 +24,8 @@ namespace SP\Infrastructure\Database; +use Aura\SqlQuery\Common\SelectInterface; +use Aura\SqlQuery\QueryInterface; use Exception; use PDO; use PDOStatement; @@ -41,12 +43,12 @@ use SP\Core\Exceptions\SPException; */ final class Database implements DatabaseInterface { + protected DbStorageInterface $dbHandler; protected int $numRows = 0; protected int $numFields = 0; protected ?array $lastResult = null; - protected DbStorageInterface $dbHandler; - private ?int $lastId = null; private EventDispatcher $eventDispatcher; + private ?int $lastId = null; /** * DB constructor. @@ -93,7 +95,7 @@ final class Database implements DatabaseInterface */ public function doSelect(QueryData $queryData, bool $fullCount = false): QueryResult { - if ($queryData->getQuery() === '') { + if ($queryData->getQuery()->getStatement()) { throw new QueryException($queryData->getOnErrorMessage(), SPException::ERROR, __u('Blank query')); } @@ -130,14 +132,14 @@ final class Database implements DatabaseInterface */ public function doQuery(QueryData $queryData): QueryResult { - $stmt = $this->prepareQueryData($queryData); + $stmt = $this->prepareQueryData($queryData->getQuery()); $this->eventDispatcher->notifyEvent( 'database.query', - new Event($this, EventMessage::factory()->addDescription($queryData->getQuery())) + new Event($this, EventMessage::factory()->addDescription($queryData->getQuery()->getStatement())) ); - if (preg_match("/^(select|show)\s/i", $queryData->getQuery())) { + if ($queryData->getQuery() instanceof SelectInterface) { $this->numFields = $stmt->columnCount(); return new QueryResult($this->fetch($queryData, $stmt)); @@ -149,8 +151,7 @@ final class Database implements DatabaseInterface /** * Asociar los parámetros de la consulta utilizando el tipo adecuado * - * @param QueryData $queryData Los datos de la consulta - * @param bool $isCount Indica si es una consulta de contador de registros + * @param QueryInterface $query Los datos de la consulta * @param array $options * * @return \PDOStatement @@ -158,25 +159,16 @@ final class Database implements DatabaseInterface * @throws \SP\Core\Exceptions\QueryException */ private function prepareQueryData( - QueryData $queryData, - bool $isCount = false, + QueryInterface $query, array $options = [] ): PDOStatement { - $query = $queryData->getQuery(); - $params = $queryData->getParams(); - - if ($isCount === true) { - $query = $queryData->getQueryCount(); - $params = $this->getParamsForCount($queryData); - } - try { $connection = $this->dbHandler->getConnection(); - if (count($params) !== 0) { - $stmt = $connection->prepare($query, $options); + if (count($query->getBindValues()) !== 0) { + $stmt = $connection->prepare($query->getStatement(), $options); - foreach ($params as $param => $value) { + foreach ($query->getBindValues() as $param => $value) { // Si la clave es un número utilizamos marcadores de posición "?" en // la consulta. En caso contrario marcadores de nombre $param = is_int($param) ? $param + 1 : ':'.$param; @@ -223,6 +215,8 @@ final class Database implements DatabaseInterface /** * Strips out the unused params from the query count + * + * TODO: remove?? */ private function getParamsForCount(QueryData $queryData): array { @@ -254,11 +248,7 @@ final class Database implements DatabaseInterface */ public function getFullRowCount(QueryData $queryData): int { - if ($queryData->getQueryCount() === '') { - return 0; - } - - $queryRes = $this->prepareQueryData($queryData, true); + $queryRes = $this->prepareQueryData($queryData->getQueryCount()); $num = (int)$queryRes->fetchColumn(); $queryRes->closeCursor(); @@ -290,7 +280,7 @@ final class Database implements DatabaseInterface ); } - return $this->prepareQueryData($queryData, false, $options); + return $this->prepareQueryData($queryData->getQuery(), $options); } /** diff --git a/lib/SP/Infrastructure/Database/DatabaseInterface.php b/lib/SP/Infrastructure/Database/DatabaseInterface.php index 2f036f1d..9898d3cf 100644 --- a/lib/SP/Infrastructure/Database/DatabaseInterface.php +++ b/lib/SP/Infrastructure/Database/DatabaseInterface.php @@ -24,6 +24,7 @@ namespace SP\Infrastructure\Database; +use Aura\SqlQuery\QueryInterface; use PDOStatement; use SP\Core\Exceptions\ConstraintException; use SP\Core\Exceptions\QueryException; diff --git a/lib/SP/Infrastructure/Database/QueryData.php b/lib/SP/Infrastructure/Database/QueryData.php index 6e67306e..a9b8c146 100644 --- a/lib/SP/Infrastructure/Database/QueryData.php +++ b/lib/SP/Infrastructure/Database/QueryData.php @@ -24,6 +24,11 @@ namespace SP\Infrastructure\Database; +use Aura\SqlQuery\Common\Select; +use Aura\SqlQuery\QueryInterface; +use SP\Core\Exceptions\QueryException; +use SP\Domain\Common\Out\SimpleModel; + /** * Class QueryData * @@ -31,18 +36,27 @@ namespace SP\Infrastructure\Database; */ final class QueryData { - protected array $params = []; - protected ?string $query = null; - protected ?string $mapClassName = null; - protected bool $useKeyPair = false; - protected ?string $select = null; - protected ?string $from = null; - protected ?string $where = null; - protected ?string $groupBy = null; - protected ?string $order = null; - protected ?string $limit = null; - protected ?string $queryCount = null; - protected ?string $onErrorMessage = null; + protected array $params = []; + protected QueryInterface $query; + protected ?string $mapClassName = SimpleModel::class; + protected bool $useKeyPair = false; + protected ?string $select = null; + protected ?string $from = null; + protected ?string $where = null; + protected ?string $groupBy = null; + protected ?string $order = null; + protected ?string $limit = null; + protected ?string $onErrorMessage = null; + + public function __construct(QueryInterface $query) + { + $this->query = $query; + } + + public static function build(QueryInterface $query): QueryData + { + return new self($query); + } /** * Añadir un parámetro a la consulta @@ -69,28 +83,16 @@ final class QueryData $this->params = $data; } - public function getQuery(): string + public function getQuery(): QueryInterface { - if (empty($this->query)) { - return $this->select. - ' '. - $this->from. - ' '. - $this->where. - ' '. - $this->groupBy. - ' '. - $this->order. - ' '. - $this->limit; - } - return $this->query; } - public function setQuery(string $query): void + public function setQuery(QueryInterface $query): QueryData { $this->query = $query; + + return $this; } public function getMapClassName(): ?string @@ -98,9 +100,11 @@ final class QueryData return $this->mapClassName; } - public function setMapClassName(string $mapClassName): void + public function setMapClassName(string $mapClassName): QueryData { $this->mapClassName = $mapClassName; + + return $this; } public function isUseKeyPair(): bool @@ -146,13 +150,26 @@ final class QueryData $this->params = array_merge($this->params, $params); } - public function getQueryCount(): string + /** + * @throws \SP\Core\Exceptions\QueryException + */ + public function getQueryCount(): QueryInterface { - if (empty($this->queryCount)) { - return 'SELECT COUNT(*) '.$this->from.' '.$this->where; + if ($this->query instanceof Select) { + $countQuery = (clone $this->query) + ->resetFlags() + ->resetCols() + ->resetOrderBy() + ->resetGroupBy() + ->resetHaving() + ->page(0); + + $countQuery->cols(['COUNT(*)']); + + return $countQuery; } - return $this->queryCount; + throw new QueryException(__u('Invalid query type for count')); } public function getFrom(): ?string @@ -191,9 +208,11 @@ final class QueryData return $this->onErrorMessage ?: __u('Error while querying'); } - public function setOnErrorMessage(string $onErrorMessage): void + public function setOnErrorMessage(string $onErrorMessage): QueryData { $this->onErrorMessage = $onErrorMessage; + + return $this; } public function setGroupBy(string $groupBy): void diff --git a/tests/SP/Repositories/AccountRepositoryTest.php b/tests/SP/Repositories/AccountRepositoryTest.php index 3daf8536..1d59bb5b 100644 --- a/tests/SP/Repositories/AccountRepositoryTest.php +++ b/tests/SP/Repositories/AccountRepositoryTest.php @@ -93,7 +93,7 @@ class AccountRepositoryTest extends UnitaryTestCase ->with($callback, false) ->willReturn($expected); - $this->assertEquals($expected, $this->accountRepository->getPasswordForId(1, new QueryCondition())); + $this->assertEquals($expected, $this->accountRepository->getPasswordForId(1)); } public function testGetPasswordHistoryForId(): void diff --git a/tests/SP/Services/Account/AccountSearchServiceTest.php b/tests/SP/Services/Account/AccountSearchServiceTest.php index 229ab255..b2651649 100644 --- a/tests/SP/Services/Account/AccountSearchServiceTest.php +++ b/tests/SP/Services/Account/AccountSearchServiceTest.php @@ -1,10 +1,10 @@ . + * along with sysPass. If not, see . */ namespace SP\Tests\Services\Account; @@ -34,7 +34,7 @@ use SP\Core\Exceptions\QueryException; use SP\Core\Exceptions\SPException; use SP\DataModel\UserPreferencesData; use SP\Domain\Account\AccountSearchServiceInterface; -use SP\Domain\Account\Services\AccountSearchFilter; +use SP\Domain\Account\Search\AccountSearchFilter; use SP\Domain\Account\Services\AccountSearchItem; use SP\Domain\Account\Services\AccountSearchService; use SP\Domain\User\Services\UserLoginResponse; @@ -154,7 +154,7 @@ class AccountSearchServiceTest extends DatabaseTestCase $searchFilter->setCategoryId($id); // Comprobar un Id de categoría - $result = self::$service->processSearchResults($searchFilter); + $result = self::$service->getByFilter($searchFilter); $this->assertInstanceOf(QueryResult::class, $result); if ($rows > 0) { @@ -181,7 +181,7 @@ class AccountSearchServiceTest extends DatabaseTestCase $searchFilter->setLimitCount(10); $searchFilter->setCategoryId(10); - $result = self::$service->processSearchResults($searchFilter); + $result = self::$service->getByFilter($searchFilter); $this->assertInstanceOf(QueryResult::class, $result); $this->assertEquals(0, $result->getNumRows()); $this->assertCount(0, $result->getDataAsArray()); @@ -203,7 +203,7 @@ class AccountSearchServiceTest extends DatabaseTestCase $searchFilter->setLimitCount(10); $searchFilter->setClientId($id); - $result = self::$service->processSearchResults($searchFilter); + $result = self::$service->getByFilter($searchFilter); $this->assertInstanceOf(QueryResult::class, $result); $this->assertEquals($rows, $result->getNumRows()); @@ -240,7 +240,7 @@ class AccountSearchServiceTest extends DatabaseTestCase $searchFilter->setClientId($clientId); $searchFilter->setCategoryId($categoryId); - $result = self::$service->processSearchResults($searchFilter); + $result = self::$service->getByFilter($searchFilter); $this->assertInstanceOf(QueryResult::class, $result); $this->assertEquals($rows, $result->getNumRows()); @@ -264,7 +264,7 @@ class AccountSearchServiceTest extends DatabaseTestCase $searchFilter->setLimitCount(10); $searchFilter->setClientId(10); - $result = self::$service->processSearchResults($searchFilter); + $result = self::$service->getByFilter($searchFilter); $this->assertInstanceOf(QueryResult::class, $result); $this->assertEquals(0, $result->getNumRows()); $this->assertCount(0, $result->getDataAsArray()); @@ -286,7 +286,7 @@ class AccountSearchServiceTest extends DatabaseTestCase $searchFilter->setLimitCount(10); $searchFilter->setTxtSearch($string); - $result = self::$service->processSearchResults($searchFilter); + $result = self::$service->getByFilter($searchFilter); $this->assertInstanceOf(QueryResult::class, $result); $this->assertEquals($rows, $result->getNumRows()); @@ -315,7 +315,7 @@ class AccountSearchServiceTest extends DatabaseTestCase $searchFilter->setLimitCount(10); $searchFilter->setSearchFavorites(true); - $result = self::$service->processSearchResults($searchFilter); + $result = self::$service->getByFilter($searchFilter); $this->assertInstanceOf(QueryResult::class, $result); $this->assertEquals($rows, $result->getNumRows()); @@ -347,7 +347,7 @@ class AccountSearchServiceTest extends DatabaseTestCase $searchFilter->setFilterOperator($operator); $searchFilter->setTagsId($tagsId); - $result = self::$service->processSearchResults($searchFilter); + $result = self::$service->getByFilter($searchFilter); $this->assertInstanceOf(QueryResult::class, $result); /** @var AccountSearchItem[] $data */ diff --git a/tests/SP/Services/Account/AccountServiceTest.php b/tests/SP/Services/Account/AccountServiceTest.php index 29e171f7..d2bebb31 100644 --- a/tests/SP/Services/Account/AccountServiceTest.php +++ b/tests/SP/Services/Account/AccountServiceTest.php @@ -40,12 +40,12 @@ use SP\DataModel\AccountVData; use SP\DataModel\ItemSearchData; use SP\DataModel\ProfileData; use SP\Domain\Account\AccountHistoryServiceInterface; +use SP\Domain\Account\Search\AccountSearchFilter; use SP\Domain\Account\Out\AccountData; use SP\Domain\Account\Services\AccountBulkRequest; use SP\Domain\Account\Services\AccountHistoryService; use SP\Domain\Account\Services\AccountPasswordRequest; use SP\Domain\Account\Services\AccountRequest; -use SP\Domain\Account\Services\AccountSearchFilter; use SP\Domain\Account\Services\AccountService; use SP\Domain\Common\Services\ServiceException; use SP\Domain\User\Services\UserLoginResponse; diff --git a/tests/SP/Services/Import/KeepassImportTest.php b/tests/SP/Services/Import/KeepassImportTest.php index eb7568f5..5a6f9e98 100644 --- a/tests/SP/Services/Import/KeepassImportTest.php +++ b/tests/SP/Services/Import/KeepassImportTest.php @@ -1,10 +1,10 @@ . + * along with sysPass. If not, see . */ namespace SP\Tests\Services\Import; @@ -34,7 +34,7 @@ use SP\Core\Exceptions\ConstraintException; use SP\Core\Exceptions\QueryException; use SP\Core\Exceptions\SPException; use SP\DataModel\AccountSearchVData; -use SP\Domain\Account\Services\AccountSearchFilter; +use SP\Domain\Account\Search\AccountSearchFilter; use SP\Domain\Account\Services\AccountService; use SP\Domain\Category\Services\CategoryService; use SP\Domain\Client\Services\ClientService;