diff --git a/app/dependencies.php b/app/dependencies.php index a69ce4af..e3b38321 100644 --- a/app/dependencies.php +++ b/app/dependencies.php @@ -17,6 +17,7 @@ use Monolog\Logger; use Monolog\Processor\UidProcessor; use Nyholm\Psr7\Factory\Psr17Factory; +use Psr\Cache\CacheItemPoolInterface; use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; use PUGX\Poser\Poser; @@ -25,6 +26,11 @@ use PUGX\Poser\Render\SvgPlasticRender; use Slim\HttpCache\CacheProvider; use Slim\Views\Twig; +use Stash\Driver\Composite; +use Stash\Driver\Ephemeral; +use Stash\Driver\FileSystem; +use Stash\Driver\Redis; +use Stash\Pool; use function DI\autowire; return static function (ContainerBuilder $containerBuilder): void { @@ -44,6 +50,43 @@ new AmqpTransport($settings->getString('queue.dsn')) ); }, + CacheItemPoolInterface::class => function (ContainerInterface $container): Pool { + $settings = $container->get(SettingsInterface::class); + + $drivers = [ + new Ephemeral() + ]; + + if ($settings->has('cache.redis')) { + $dsn = parse_url($settings->getString('cache.redis')); + $drivers[] = new Redis( + [ + 'servers' => [ + 'server' => $dsn['host'] ?? 'localhost', + 'port' => $dsn['port'] ?? 6379 + ] + ] + ); + } + + $drivers[] = new FileSystem( + [ + 'path' => __DIR__ . '/../var/cache' + ] + ); + + if (count($drivers) > 1) { + $driver = new Composite( + [ + 'drivers' => $drivers + ] + ); + + return new Pool($driver); + } + + return new Pool($drivers[0]); + }, Consumer::class => function (ContainerInterface $container): Consumer { return new Consumer( $container->get(Bus::class), diff --git a/app/repositories.php b/app/repositories.php index f3240968..487f1071 100644 --- a/app/repositories.php +++ b/app/repositories.php @@ -5,20 +5,54 @@ use App\Domain\Package\PackageRepositoryInterface; use App\Domain\Stats\StatsRepositoryInterface; use App\Domain\Version\VersionRepositoryInterface; +use App\Infrastructure\Persistence\Dependency\CachedDependencyRepository; use App\Infrastructure\Persistence\Dependency\PdoDependencyRepository; +use App\Infrastructure\Persistence\Package\CachedPackageRepository; use App\Infrastructure\Persistence\Package\PdoPackageRepository; +use App\Infrastructure\Persistence\Stats\CachedStatsRepository; use App\Infrastructure\Persistence\Stats\PdoStatsRepository; +use App\Infrastructure\Persistence\Version\CachedVersionRepository; use App\Infrastructure\Persistence\Version\PdoVersionRepository; use DI\ContainerBuilder; +use Psr\Cache\CacheItemPoolInterface; +use Psr\Container\ContainerInterface; use function DI\autowire; return static function (ContainerBuilder $containerBuilder): void { $containerBuilder->addDefinitions( [ - DependencyRepositoryInterface::class => autowire(PdoDependencyRepository::class), - PackageRepositoryInterface::class => autowire(PdoPackageRepository::class), - StatsRepositoryInterface::class => autowire(PdoStatsRepository::class), - VersionRepositoryInterface::class => autowire(PdoVersionRepository::class) + // Dependency + PdoDependencyRepository::class => autowire(PdoDependencyRepository::class), + DependencyRepositoryInterface::class => static function (ContainerInterface $container): CachedDependencyRepository { + return new CachedDependencyRepository( + $container->get(PdoDependencyRepository::class), + $container->get(CacheItemPoolInterface::class) + ); + }, + // Package + PdoPackageRepository::class => autowire(PdoPackageRepository::class), + PackageRepositoryInterface::class => static function (ContainerInterface $container): CachedPackageRepository { + return new CachedPackageRepository( + $container->get(PdoPackageRepository::class), + $container->get(CacheItemPoolInterface::class) + ); + }, + // Stats + PdoStatsRepository::class => autowire(PdoStatsRepository::class), + StatsRepositoryInterface::class => static function (ContainerInterface $container): CachedStatsRepository { + return new CachedStatsRepository( + $container->get(PdoStatsRepository::class), + $container->get(CacheItemPoolInterface::class) + ); + }, + // Version + PdoVersionRepository::class => autowire(PdoVersionRepository::class), + VersionRepositoryInterface::class => static function (ContainerInterface $container): CachedVersionRepository { + return new CachedVersionRepository( + $container->get(PdoVersionRepository::class), + $container->get(CacheItemPoolInterface::class) + ); + } ] ); }; diff --git a/composer.json b/composer.json index 922a4680..7ce9cb99 100644 --- a/composer.json +++ b/composer.json @@ -44,12 +44,16 @@ "nyholm/psr7": "^1.5", "nyholm/psr7-server": "^1.0", "php-di/php-di": "^6.3", + "psr/cache": "^1.0", + "psr/container": "^1.0", + "psr/log": "^2.0", "ramsey/collection": "^1.2", "robmorgan/phinx": "^0.12.10", "slim/http-cache": "^1.1", "slim/slim": "^4.9", "slim/twig-view": "^3.3", "symfony/console": "^6.0", + "tedivm/stash": "^0.17", "vlucas/phpdotenv": "^5.4" }, "require-dev": { diff --git a/composer.lock b/composer.lock index 4df5fdf8..915627cd 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": "76af0a814099b0ea7ea50b87fa202a41", + "content-hash": "8fabc4549faa2aa176c74a366e2ce8e1", "packages": [ { "name": "badges/poser", @@ -1657,6 +1657,55 @@ ], "time": "2021-12-04T23:24:31+00:00" }, + { + "name": "psr/cache", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "support": { + "source": "https://github.com/php-fig/cache/tree/master" + }, + "time": "2016-08-06T20:24:11+00:00" + }, { "name": "psr/container", "version": "1.1.2", @@ -2656,25 +2705,25 @@ }, { "name": "symfony/deprecation-contracts", - "version": "v3.0.0", + "version": "v2.5.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "c726b64c1ccfe2896cb7df2e1331c357ad1c8ced" + "reference": "6f981ee24cf69ee7ce9736146d1c57c2780598a8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/c726b64c1ccfe2896cb7df2e1331c357ad1c8ced", - "reference": "c726b64c1ccfe2896cb7df2e1331c357ad1c8ced", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/6f981ee24cf69ee7ce9736146d1c57c2780598a8", + "reference": "6f981ee24cf69ee7ce9736146d1c57c2780598a8", "shasum": "" }, "require": { - "php": ">=8.0.2" + "php": ">=7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "3.0-dev" + "dev-main": "2.5-dev" }, "thanks": { "name": "symfony/contracts", @@ -2703,7 +2752,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.0.0" + "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.0" }, "funding": [ { @@ -2719,7 +2768,7 @@ "type": "tidelift" } ], - "time": "2021-11-01T23:48:49+00:00" + "time": "2021-07-12T14:48:14+00:00" }, { "name": "symfony/filesystem", @@ -3426,21 +3475,22 @@ }, { "name": "symfony/service-contracts", - "version": "v2.4.1", + "version": "v2.5.0", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "d664541b99d6fb0247ec5ff32e87238582236204" + "reference": "1ab11b933cd6bc5464b08e81e2c5b07dec58b0fc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/d664541b99d6fb0247ec5ff32e87238582236204", - "reference": "d664541b99d6fb0247ec5ff32e87238582236204", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/1ab11b933cd6bc5464b08e81e2c5b07dec58b0fc", + "reference": "1ab11b933cd6bc5464b08e81e2c5b07dec58b0fc", "shasum": "" }, "require": { "php": ">=7.2.5", - "psr/container": "^1.1" + "psr/container": "^1.1", + "symfony/deprecation-contracts": "^2.1" }, "conflict": { "ext-psr": "<1.1|>=2" @@ -3451,7 +3501,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "2.4-dev" + "dev-main": "2.5-dev" }, "thanks": { "name": "symfony/contracts", @@ -3488,7 +3538,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v2.4.1" + "source": "https://github.com/symfony/service-contracts/tree/v2.5.0" }, "funding": [ { @@ -3504,7 +3554,7 @@ "type": "tidelift" } ], - "time": "2021-11-04T16:37:19+00:00" + "time": "2021-11-04T16:48:04+00:00" }, { "name": "symfony/string", @@ -3591,6 +3641,82 @@ ], "time": "2022-01-02T09:55:41+00:00" }, + { + "name": "tedivm/stash", + "version": "v0.17.0", + "source": { + "type": "git", + "url": "https://github.com/tedious/Stash.git", + "reference": "7a898d86277373b80de432538545e65870e2594e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/tedious/Stash/zipball/7a898d86277373b80de432538545e65870e2594e", + "reference": "7a898d86277373b80de432538545e65870e2594e", + "shasum": "" + }, + "require": { + "php": ">7.0", + "psr/cache": "~1.0" + }, + "provide": { + "psr/cache-implementation": "1.0.0" + }, + "require-dev": { + "dms/phpunit-arraysubset-asserts": "^0.4.0", + "friendsofphp/php-cs-fixer": "^2.8", + "php": "^7.2|^8.0", + "php-coveralls/php-coveralls": "^2.0", + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Stash\\": "src/Stash/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Robert Hafner", + "email": "tedivm@tedivm.com" + }, + { + "name": "Josh Hall-Bachner", + "email": "charlequin@gmail.com" + } + ], + "description": "The place to keep your cache.", + "homepage": "http://github.com/tedious/Stash", + "keywords": [ + "apc", + "cache", + "caching", + "memcached", + "psr-6", + "psr6", + "redis", + "sessions" + ], + "support": { + "issues": "https://github.com/tedious/Stash/issues", + "source": "https://github.com/tedious/Stash/tree/v0.17.0" + }, + "funding": [ + { + "url": "https://github.com/tedivm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/tedivm/stash", + "type": "tidelift" + } + ], + "time": "2022-02-21T22:01:48+00:00" + }, { "name": "twig/twig", "version": "v3.3.8", diff --git a/src/Domain/Dependency/DependencyRepositoryInterface.php b/src/Domain/Dependency/DependencyRepositoryInterface.php index a735ad4a..453a89bd 100644 --- a/src/Domain/Dependency/DependencyRepositoryInterface.php +++ b/src/Domain/Dependency/DependencyRepositoryInterface.php @@ -10,7 +10,7 @@ public function create( string $name, string $constraint, bool $development = false, - DependencyStatusEnum $status = DependencyStatusEnum::Unknown, + DependencyStatusEnum $status = DependencyStatusEnum::Unknown ): Dependency; public function all(): DependencyCollection; diff --git a/src/Infrastructure/Persistence/Dependency/CachedDependencyRepository.php b/src/Infrastructure/Persistence/Dependency/CachedDependencyRepository.php new file mode 100644 index 00000000..533722cb --- /dev/null +++ b/src/Infrastructure/Persistence/Dependency/CachedDependencyRepository.php @@ -0,0 +1,104 @@ +dependencyRepository = $dependencyRepository; + $this->cacheItemPool = $cacheItemPool; + } + + public function create( + int $versionId, + string $name, + string $constraint, + bool $development = false, + DependencyStatusEnum $status = DependencyStatusEnum::Unknown + ): Dependency { + return $this->dependencyRepository->create( + $versionId, + $name, + $constraint, + $development, + $status + ); + } + + public function all(): DependencyCollection { + $item = $this->cacheItemPool->getItem('/dependency'); + $dependencyCol = $item->get(); + if ($item->isHit() === false) { + $dependencyCol = $this->dependencyRepository->all(); + + $item->set($dependencyCol); + $item->expiresAfter(3600); + + $this->cacheItemPool->save($item); + } + + return $dependencyCol; + } + + /** + * @throws \App\Domain\Dependency\DependencyNotFoundException + */ + public function get(int $id): Dependency { + $item = $this->cacheItemPool->getItem("/dependency/${id}"); + $dependency = $item->get(); + if ($item->isHit() === false) { + $dependency = $this->dependencyRepository->get($id); + + $item->set($dependency); + $item->expiresAfter(3600); + + $this->cacheItemPool->save($item); + } + + return $dependency; + } + + public function find(array $query): DependencyCollection { + $key = http_build_query($query); + $item = $this->cacheItemPool->getItem("/dependency/find/{$key}"); + $dependencyCol = $item->get(); + if ($item->isHit() === false) { + $dependencyCol = $this->dependencyRepository->find($query); + + $item->set($dependencyCol); + $item->expiresAfter(3600); + + $this->cacheItemPool->save($item); + } + + return $dependencyCol; + } + + public function save(Dependency $dependency): Dependency { + $dependency = $this->dependencyRepository->save($dependency); + + $this->cacheItemPool->deleteItem('/dependency/' . $dependency->getId()); + + return $dependency; + } + + public function update(Dependency $dependency): Dependency { + $dependency = $this->dependencyRepository->update($dependency); + + $this->cacheItemPool->deleteItem('/dependency/' . $dependency->getId()); + + return $dependency; + } +} diff --git a/src/Infrastructure/Persistence/Dependency/PdoDependencyRepository.php b/src/Infrastructure/Persistence/Dependency/PdoDependencyRepository.php index 5988c65f..13c06a84 100644 --- a/src/Infrastructure/Persistence/Dependency/PdoDependencyRepository.php +++ b/src/Infrastructure/Persistence/Dependency/PdoDependencyRepository.php @@ -49,7 +49,7 @@ public function create( string $name, string $constraint, bool $development = false, - DependencyStatusEnum $status = DependencyStatusEnum::Unknown, + DependencyStatusEnum $status = DependencyStatusEnum::Unknown ): Dependency { return $this->save( new Dependency( diff --git a/src/Infrastructure/Persistence/Package/CachedPackageRepository.php b/src/Infrastructure/Persistence/Package/CachedPackageRepository.php new file mode 100644 index 00000000..0b3ed3bd --- /dev/null +++ b/src/Infrastructure/Persistence/Package/CachedPackageRepository.php @@ -0,0 +1,137 @@ +packageRepository = $packageRepository; + $this->cacheItemPool = $cacheItemPool; + } + + public function create(string $name): Package { + return $this->packageRepository->create($name); + } + + public function all(): PackageCollection { + $item = $this->cacheItemPool->getItem('/package'); + $packageCol = $item->get(); + if ($item->isHit() === false) { + $packageCol = $this->packageRepository->all(); + + $item->set($packageCol); + $item->expiresAfter(3600); + + $this->cacheItemPool->save($item); + } + + return $packageCol; + } + + public function findPopular(int $limit = 10): PackageCollection { + $item = $this->cacheItemPool->getItem("/package/popular/${limit}"); + $packageCol = $item->get(); + if ($item->isHit() === false) { + $packageCol = $this->packageRepository->findPopular($limit); + + $item->set($packageCol); + $item->expiresAfter(3600); + + $this->cacheItemPool->save($item); + } + + return $packageCol; + } + + public function exists(string $name): bool { + $item = $this->cacheItemPool->getItem("/package/${name}/exists"); + $exists = $item->get(); + if ($item->isHit() === false) { + $exists = $this->packageRepository->exists($name); + + $item->set($exists); + $item->expiresAfter(3600); + + $this->cacheItemPool->save($item); + } + + return $exists; + } + + /** + * @throws \App\Domain\Package\PackageNotFoundException + */ + public function get(string $name): Package { + $item = $this->cacheItemPool->getItem("/package/${name}"); + $package = $item->get(); + if ($item->isHit() === false) { + $package = $this->packageRepository->get($name); + + $item->set($package); + $item->expiresAfter(3600); + + $this->cacheItemPool->save($item); + } + + return $package; + } + + public function find(array $query): PackageCollection { + $key = http_build_query($query); + $item = $this->cacheItemPool->getItem("/package/find/{$key}"); + $packageCol = $item->get(); + if ($item->isHit() === false) { + $packageCol = $this->packageRepository->find($query); + + $item->set($packageCol); + $item->expiresAfter(3600); + + $this->cacheItemPool->save($item); + } + + return $packageCol; + } + + public function findMatching(array $query): PackageCollection { + $key = http_build_query($query); + $item = $this->cacheItemPool->getItem("/package/matching/{$key}"); + $packageCol = $item->get(); + if ($item->isHit() === false) { + $packageCol = $this->packageRepository->findMatching($query); + + $item->set($packageCol); + $item->expiresAfter(3600); + + $this->cacheItemPool->save($item); + } + + return $packageCol; + } + + public function save(Package $package): Package { + $package = $this->packageRepository->save($package); + + $this->cacheItemPool->deleteItem('/package/' . $package->getName()); + + return $package; + } + + public function update(Package $package): Package { + $package = $this->packageRepository->update($package); + + $this->cacheItemPool->deleteItem('/package/' . $package->getName()); + + return $package; + } +} diff --git a/src/Infrastructure/Persistence/Stats/CachedStatsRepository.php b/src/Infrastructure/Persistence/Stats/CachedStatsRepository.php new file mode 100644 index 00000000..f79cef3f --- /dev/null +++ b/src/Infrastructure/Persistence/Stats/CachedStatsRepository.php @@ -0,0 +1,143 @@ +statsRepository = $statsRepository; + $this->cacheItemPool = $cacheItemPool; + } + + public function create( + string $packageName, + int $githubStars = 0, + int $githubWatchers = 0, + int $githubForks = 0, + int $dependents = 0, + int $suggesters = 0, + int $favers = 0, + int $totalDownloads = 0, + int $monthlyDownloads = 0, + int $dailyDownloads = 0 + ): Stats { + return $this->statsRepository->create( + $packageName, + $githubStars, + $githubWatchers, + $githubForks, + $dependents, + $suggesters, + $favers, + $totalDownloads, + $monthlyDownloads, + $dailyDownloads + ); + } + + public function all(): StatsCollection { + $item = $this->cacheItemPool->getItem('/stats'); + $statsCol = $item->get(); + if ($item->isHit() === false) { + $statsCol = $this->statsRepository->all(); + + $item->set($statsCol); + $item->expiresAfter(3600); + + $this->cacheItemPool->save($item); + } + + return $statsCol; + } + + public function findPopular(): StatsCollection { + $item = $this->cacheItemPool->getItem('/stats/popular'); + $statsCol = $item->get(); + if ($item->isHit() === false) { + $statsCol = $this->statsRepository->findPopular(); + + $item->set($statsCol); + $item->expiresAfter(3600); + + $this->cacheItemPool->save($item); + } + + return $statsCol; + } + + public function exists(string $packageName): bool { + $item = $this->cacheItemPool->getItem("/stats/${packageName}/exists"); + $exists = $item->get(); + if ($item->isHit() === false) { + $exists = $this->statsRepository->exists($packageName); + + $item->set($exists); + $item->expiresAfter(3600); + + $this->cacheItemPool->save($item); + } + + return $exists; + } + + /** + * @throws \App\Domain\Stats\StatsNotFoundException + */ + public function get(string $packageName): Stats { + $item = $this->cacheItemPool->getItem("/stats/${packageName}"); + $stats = $item->get(); + if ($item->isHit() === false) { + $stats = $this->statsRepository->get($packageName); + + $item->set($stats); + $item->expiresAfter(3600); + + $this->cacheItemPool->save($item); + } + + return $stats; + } + + public function find(array $query): StatsCollection { + $key = http_build_query($query); + $item = $this->cacheItemPool->getItem("/stats/find/{$key}"); + $statsCol = $item->get(); + if ($item->isHit() === false) { + $statsCol = $this->statsRepository->find($query); + + $item->set($statsCol); + $item->expiresAfter(3600); + + $this->cacheItemPool->save($item); + } + + return $statsCol; + } + + public function save(Stats $stats): Stats { + $stats = $this->statsRepository->save($stats); + + $this->cacheItemPool->deleteItem('/stats/' . $stats->getPackageName()); + + return $stats; + } + + public function update(Stats $stats): Stats { + $stats = $this->statsRepository->update($stats); + + $this->cacheItemPool->deleteItem('/stats/' . $stats->getPackageName()); + + return $stats; + } +} diff --git a/src/Infrastructure/Persistence/Version/CachedVersionRepository.php b/src/Infrastructure/Persistence/Version/CachedVersionRepository.php new file mode 100644 index 00000000..07392d48 --- /dev/null +++ b/src/Infrastructure/Persistence/Version/CachedVersionRepository.php @@ -0,0 +1,104 @@ +versionRepository = $versionRepository; + $this->cacheItemPool = $cacheItemPool; + } + + public function create( + string $number, + string $normalized, + string $packageName, + bool $release, + VersionStatusEnum $status = VersionStatusEnum::Unknown + ): Version { + return $this->versionRepository->create( + $number, + $normalized, + $packageName, + $release, + $status + ); + } + + public function all(): VersionCollection { + $item = $this->cacheItemPool->getItem('/version'); + $versionCol = $item->get(); + if ($item->isHit() === false) { + $versionCol = $this->versionRepository->all(); + + $item->set($versionCol); + $item->expiresAfter(3600); + + $this->cacheItemPool->save($item); + } + + return $versionCol; + } + + /** + * @throws \App\Domain\Version\VersionNotFoundException + */ + public function get(int $id): Version { + $item = $this->cacheItemPool->getItem("/version/${id}"); + $version = $item->get(); + if ($item->isHit() === false ) { + $version = $this->versionRepository->get($id); + + $item->set($version); + $item->expiresAfter(3600); + + $this->cacheItemPool->save($item); + } + + return $version; + } + + public function find(array $query): VersionCollection { + $key = http_build_query($query); + $item = $this->cacheItemPool->getItem("/version/find/{$key}"); + $versionCol = $item->get(); + if ($item->isHit() === false) { + $versionCol = $this->versionRepository->find($query); + + $item->set($versionCol); + $item->expiresAfter(3600); + + $this->cacheItemPool->save($item); + } + + return $versionCol; + } + + public function save(Version $version): Version { + $version = $this->versionRepository->save($version); + + $this->cacheItemPool->deleteItem('/version/' . $version->getId()); + + return $version; + } + + public function update(Version $version): Version { + $version = $this->versionRepository->update($version); + + $this->cacheItemPool->deleteItem('/version/' . $version->getId()); + + return $version; + } +}