feat: add config redis cache, categories cache (#44)

This commit is contained in:
2026-01-05 13:14:54 +03:00
committed by Nikita Kiselev
parent 3a1f8dbf94
commit 0798f5c3e9
12 changed files with 90 additions and 81 deletions

View File

@@ -19,6 +19,7 @@
3. **Следуй соглашениям именования проекта** 3. **Следуй соглашениям именования проекта**
4. **Тестируй изменения перед коммитом** 4. **Тестируй изменения перед коммитом**
5. **Документируй публичные API** 5. **Документируй публичные API**
6. **Комментарии только на английском языке и только если они действительно оправданы**
### Правила коммитов ### Правила коммитов

View File

@@ -32,7 +32,6 @@ services:
- PHP_IDE_CONFIG=serverName=telecart - PHP_IDE_CONFIG=serverName=telecart
- php.session.gc_maxlifetime=28800 - php.session.gc_maxlifetime=28800
- php.session.cookie_lifetime=0 - php.session.cookie_lifetime=0
- TELECART_CACHE_DRIVER=database
- TELECART_REDIS_HOST=redis - TELECART_REDIS_HOST=redis
- TELECART_REDIS_PORT=6379 - TELECART_REDIS_PORT=6379
- TELECART_REDIS_DATABASE=0 - TELECART_REDIS_DATABASE=0

View File

@@ -1,3 +1,8 @@
APP_DEBUG=true APP_DEBUG=true
PULSE_API_HOST=https://pulse.telecart.pro/api/ PULSE_API_HOST=https://pulse.telecart.pro/api/
PULSE_HEARTBEAT_SECRET=c5261f5d-529e-45ad-a69c-9778b755b7cb PULSE_HEARTBEAT_SECRET=c5261f5d-529e-45ad-a69c-9778b755b7cb
TELECART_CACHE_DRIVER=redis
#TELECART_REDIS_HOST=redis
#TELECART_REDIS_PORT=6379
#TELECART_REDIS_DATABASE=0

View File

@@ -1,3 +1,7 @@
APP_DEBUG=false APP_DEBUG=false
PULSE_API_HOST=http://host.docker.internal:8086/api/ PULSE_API_HOST=http://host.docker.internal:8086/api/
PULSE_HEARTBEAT_SECRET=c5261f5d-529e-45ad-a69c-9778b755b7cb PULSE_HEARTBEAT_SECRET=c5261f5d-529e-45ad-a69c-9778b755b7cb
TELECART_CACHE_DRIVER=database
TELECART_REDIS_HOST=redis
TELECART_REDIS_PORT=6379
TELECART_REDIS_DATABASE=0

View File

@@ -1,3 +1,7 @@
APP_DEBUG=false APP_DEBUG=false
PULSE_API_HOST=https://pulse.telecart.pro/api/ PULSE_API_HOST=https://pulse.telecart.pro/api/
PULSE_HEARTBEAT_SECRET=c5261f5d-529e-45ad-a69c-9778b755b7cb PULSE_HEARTBEAT_SECRET=c5261f5d-529e-45ad-a69c-9778b755b7cb
TELECART_CACHE_DRIVER=mysql
TELECART_REDIS_HOST=redis
TELECART_REDIS_PORT=6379
TELECART_REDIS_DATABASE=0

View File

@@ -1,30 +0,0 @@
<?php
namespace Bastion\Tasks;
use DateInterval;
use Openguru\OpenCartFramework\Cache\CacheInterface;
use Openguru\OpenCartFramework\MaintenanceTasks\BaseMaintenanceTask;
use Psr\Log\LoggerInterface;
class CachePruneTask extends BaseMaintenanceTask
{
private CacheInterface $cache;
public function __construct(LoggerInterface $logger, CacheInterface $cache)
{
parent::__construct($logger);
$this->cache = $cache;
}
public function handle(): void
{
$this->cache->prune();
}
public function interval(): ?DateInterval
{
return new DateInterval('P1D');
}
}

View File

@@ -1,11 +1,9 @@
<?php <?php
use Bastion\Tasks\CachePruneTask;
use Bastion\Tasks\CleanUpOldAssetsTask; use Bastion\Tasks\CleanUpOldAssetsTask;
return [ return [
'tasks' => [ 'tasks' => [
CleanUpOldAssetsTask::class, CleanUpOldAssetsTask::class,
CachePruneTask::class,
], ],
]; ];

View File

@@ -56,8 +56,7 @@ class Application extends Container implements LoggerAwareInterface
return new Settings($container->getConfigValue()); return new Settings($container->getConfigValue());
}); });
$dotenv = Dotenv::createImmutable(__DIR__ . '/../'); $this->loadEnvironmentVariables();
$dotenv->load();
$errorHandler = new ErrorHandler( $errorHandler = new ErrorHandler(
$this->get(LoggerInterface::class), $this->get(LoggerInterface::class),
@@ -172,4 +171,30 @@ class Application extends Container implements LoggerAwareInterface
{ {
$this->logger = $logger; $this->logger = $logger;
} }
/**
* Loads environment variables from .env files.
* First loads internal .env (from phar or module directory),
* then external .env (if exists next to phar/directory) which overrides values.
*/
private function loadEnvironmentVariables(): void
{
if (!defined('BP_PHAR_BASE_PATH') || !defined('BP_REAL_BASE_PATH')) {
$dotenv = Dotenv::createMutable(__DIR__ . '/../');
$dotenv->load();
return;
}
$internalEnvPath = BP_PHAR_BASE_PATH;
if (is_readable($internalEnvPath . '/.env')) {
$dotenv = Dotenv::createImmutable($internalEnvPath);
$dotenv->load();
}
$externalEnvPath = BP_REAL_BASE_PATH;
if (is_readable($externalEnvPath . '/.env')) {
$dotenv = Dotenv::createImmutable($externalEnvPath);
$dotenv->load();
}
}
} }

View File

@@ -11,6 +11,4 @@ interface CacheInterface
public function delete(string $key): void; public function delete(string $key): void;
public function clear(): void; public function clear(): void;
public function prune(): void;
} }

View File

@@ -41,9 +41,4 @@ class SymfonyMySqlCache implements CacheInterface
{ {
$this->cache->clear(); $this->cache->clear();
} }
public function prune(): void
{
$this->cache->prune();
}
} }

View File

@@ -41,9 +41,4 @@ class SymfonyRedisCache implements CacheInterface
{ {
$this->cache->clear(); $this->cache->clear();
} }
public function prune(): void
{
$this->cache->prune();
}
} }

View File

@@ -6,6 +6,7 @@ namespace App\Handlers;
use App\Services\SettingsService; use App\Services\SettingsService;
use App\Support\Utils; use App\Support\Utils;
use Openguru\OpenCartFramework\Cache\CacheInterface;
use Openguru\OpenCartFramework\Http\Request; use Openguru\OpenCartFramework\Http\Request;
use Openguru\OpenCartFramework\ImageTool\ImageFactory; use Openguru\OpenCartFramework\ImageTool\ImageFactory;
use Openguru\OpenCartFramework\QueryBuilder\Builder; use Openguru\OpenCartFramework\QueryBuilder\Builder;
@@ -21,52 +22,66 @@ class CategoriesHandler
private Builder $queryBuilder; private Builder $queryBuilder;
private ImageFactory $image; private ImageFactory $image;
private SettingsService $settings; private SettingsService $settings;
private CacheInterface $cache;
public function __construct(Builder $queryBuilder, ImageFactory $ocImageTool, SettingsService $settings) public function __construct(
{ Builder $queryBuilder,
ImageFactory $ocImageTool,
SettingsService $settings,
CacheInterface $cache
) {
$this->queryBuilder = $queryBuilder; $this->queryBuilder = $queryBuilder;
$this->image = $ocImageTool; $this->image = $ocImageTool;
$this->settings = $settings; $this->settings = $settings;
$this->cache = $cache;
} }
public function index(Request $request): JsonResponse public function index(Request $request): JsonResponse
{ {
$languageId = $this->settings->config()->getApp()->getLanguageId(); $cacheKey = 'categories.index';
$storeId = $this->settings->get('store.oc_store_id', 0);
$perPage = $request->get('perPage', 100); $categories = $this->cache->get($cacheKey);
$categoriesFlat = $this->queryBuilder->newQuery() if ($categories === null) {
->select([ $languageId = $this->settings->config()->getApp()->getLanguageId();
'categories.category_id' => 'id', $storeId = $this->settings->get('store.oc_store_id', 0);
'categories.parent_id' => 'parent_id',
'categories.image' => 'image',
'descriptions.name' => 'name',
'descriptions.description' => 'description',
])
->from(db_table('category'), 'categories')
->join(
db_table('category_description') . ' AS descriptions',
function (JoinClause $join) use ($languageId) {
$join->on('categories.category_id', '=', 'descriptions.category_id')
->where('descriptions.language_id', '=', $languageId);
}
)
->join(
new Table(db_table('category_to_store'), 'category_to_store'),
function (JoinClause $join) use ($storeId) {
$join->on('category_to_store.category_id', '=', 'categories.category_id')
->where('category_to_store.store_id', '=', $storeId);
}
)
->where('categories.status', '=', 1)
->orderBy('parent_id')
->orderBy('sort_order')
->get();
$categories = $this->buildCategoryTree($categoriesFlat); $perPage = $request->get('perPage', 100);
$categories = array_slice($categories, 0, $perPage); $categoriesFlat = $this->queryBuilder->newQuery()
->select([
'categories.category_id' => 'id',
'categories.parent_id' => 'parent_id',
'categories.image' => 'image',
'descriptions.name' => 'name',
'descriptions.description' => 'description',
])
->from(db_table('category'), 'categories')
->join(
db_table('category_description') . ' AS descriptions',
function (JoinClause $join) use ($languageId) {
$join->on('categories.category_id', '=', 'descriptions.category_id')
->where('descriptions.language_id', '=', $languageId);
}
)
->join(
new Table(db_table('category_to_store'), 'category_to_store'),
function (JoinClause $join) use ($storeId) {
$join->on('category_to_store.category_id', '=', 'categories.category_id')
->where('category_to_store.store_id', '=', $storeId);
}
)
->where('categories.status', '=', 1)
->orderBy('parent_id')
->orderBy('sort_order')
->get();
$categories = $this->buildCategoryTree($categoriesFlat);
$categories = array_slice($categories, 0, $perPage);
$this->cache->set($cacheKey, $categories, 60 * 60 * 24);
}
return new JsonResponse([ return new JsonResponse([
'data' => array_map(static function ($category) { 'data' => array_map(static function ($category) {