=============== LIBRARY RULES =============== From library maintainers: - Routes are defined with #[Route('/path', [HttpMethod::GET])] on controller methods, never in config files. - Controllers must extend RestController and be annotated with #[Controller]. - Dependencies are injected via #[Inject] in the constructor — do not instantiate services manually. - Request parameters are validated via DTO arguments annotated with #[JsonBody], #[QueryParams], #[PostBody], or #[FormDataBody]. - Validation rules come from OpenApi\Attributes\Property on DTO properties. - Exceptions extend BaseException where the code equals the HTTP status (e.g. 404, 403, 422). - Repositories extend PdoStorage and get a PDO instance via $this->getPdo(). - DI bindings (interface -> implementation) are registered in Config::$bindings or Config::setDIBindings(). - Auth is handled by extending AuthServiceAbstract — do not implement JWT logic manually. - Queue jobs implement QueueJob and are published via RabbitMQQueuePublisher or OutboxPublisher. ### Install spsfw via Symlink Source: https://github.com/tixlag/spsfw/blob/master/docs/14_spsfw_cli.md Recommended installation method for the spsfw CLI utility. Ensure the script is executable after creating the symlink. ```bash sudo ln -s /absolute/path/to/bin/spsfw/spsfw /usr/local/bin/spsfw chmod +x /absolute/path/to/bin/spsfw/spsfw ``` -------------------------------- ### Run Composer Install Source: https://github.com/tixlag/spsfw/blob/master/docs/1_getting_started.md Execute the composer install command to download and install the SpsFW framework and its dependencies. ```bash composer install ``` -------------------------------- ### Create Custom Middleware Source: https://github.com/tixlag/spsfw/blob/master/docs/5_middleware.md Example implementation of a middleware class with dependency injection support. ```php someDependency = $dep; } public function handle(Request $request): Request { // Логика, выполняемая ДО контроллера // Можно модифицировать $request $this->someDependency->log('Before controller'); return $request; } public function after(Response $response): Response { // Логика, выполняемая ПОСЛЕ контроллера // Можно модифицировать $response $response->addHeader('X-My-Middleware', 'Processed'); $this->someDependency->log('After controller'); return $response; } } ?> ``` -------------------------------- ### Generated UsersController.php Source: https://github.com/tixlag/spsfw/blob/master/docs/14_spsfw_cli.md Example of a generated controller file for a new chapter. Includes basic annotations and dependency injection setup. ```php #[Controller] #[OA\Tag(name: 'users', description: 'API для работы с users')] class UsersController extends RestController { public function __construct( #[Inject] private UsersService $usersService ) { parent::__construct(); } // TODO: Add routes here } ``` -------------------------------- ### Run Development Server Source: https://github.com/tixlag/spsfw/blob/master/docs/1_getting_started.md Command to start the built-in PHP development server. This is suitable for local development and testing. ```bash # Встроенный PHP-сервер (dev) php -S localhost:8080 index.php ``` -------------------------------- ### DI Configuration for Email Publisher Source: https://github.com/tixlag/spsfw/blob/master/docs/11_queue_workes.md Example of configuring an email publisher within a DI container using a factory. This setup is for creating publishers that utilize delayed message exchanges. ```php // В bootstrap/config — пример создания через фабрику $factory = $container->get( SpsFW Core Queue QueueClientAndPublisherFactory::class); $delayedExchange = 'delayed_notifications'; $exchangeArgs = ['x-delayed-type' => 'direct']; $container->set('publisher.email', fn() => $factory->create( 'notifications_email', $delayedExchange, 'notification.email', 'x-delayed-message', $exchangeArgs )); ``` -------------------------------- ### Configure spsfw Project Root and Namespace Source: https://github.com/tixlag/spsfw/blob/master/docs/14_spsfw_cli.md Initial setup for spsfw. Use `--set-root` to specify the project's source directory and `--set-namespace` for the base application namespace. Settings are saved in `.spsfw-config`. ```bash spsfw --set-root /var/www/my-project ``` ```bash spsfw --set-namespace App ``` ```bash spsfw --show-paths ``` -------------------------------- ### Create a Basic Users Controller Source: https://github.com/tixlag/spsfw/blob/master/docs/1_getting_started.md Example of a REST controller for managing users. It uses attributes for routing and dependency injection. This controller requires a UsersService to be available. ```php usersService->getAll()); } } ``` -------------------------------- ### Register Global Middleware Source: https://github.com/tixlag/spsfw/blob/master/docs/5_middleware.md Methods and examples for registering middleware that applies to all routes. ```php $router->addGlobalMiddleware(string $middlewareClass, array $params = []); ``` ```php // В index.php или preload.php $router = new \SpsFW\Core\Router\Router(); $router->addGlobalMiddleware(\App\Middleware\MyMiddleware::class, ['param1' => 'value1']); // ... ``` -------------------------------- ### Generated UsersService.php Source: https://github.com/tixlag/spsfw/blob/master/docs/14_spsfw_cli.md Example of a generated service file for a new chapter. Includes constructor with dependency injection. ```php class UsersService { public function __construct( #[Inject] private UsersStorage $usersStorage ) {} } ``` -------------------------------- ### Configure Large Message Handling in PHP Source: https://github.com/tixlag/spsfw/blob/master/docs/12_large_messages.md Examples for configuring the LargeMessageHandler via factory or direct client instantiation. ```php use SpsFW\Core\Queue\QueueClientAndPublisherFactory; // Large message handler создаётся автоматически с настройками по умолчанию: // - chunkSize: 8MB // - compression: включено // - checksum: md5 $factory = new QueueClientAndPublisherFactory( $rabbitConfig, $workerConfig ); $publisher = $factory->createByWorkerName('my-worker'); // Большие сообщения автоматически разбиваются на чанки ``` ```php use SpsFW\Core\Queue\QueueClientAndPublisherFactory; // Создаём handler с кастомными параметрами $largeMessageHandler = QueueClientAndPublisherFactory::createLargeMessageHandler( chunkSize: 10 * 1024 * 1024, // 10MB enableCompression: true, // сжатие GZIP checksumAlgo: 'sha256' // более надёжный checksum ); // Передаём в фабрику $factory = new QueueClientAndPublisherFactory( $rabbitConfig, $workerConfig, $largeMessageHandler ); ``` ```php $handler = QueueClientAndPublisherFactory::createLargeMessageHandler( chunkSize: 5 * 1024 * 1024, // 5MB enableCompression: false // без сжатия ); $client = new RabbitMQClient( exchange: 'my-exchange', queue: 'my-queue', routingKey: 'my-key', config: $config, largeMessageHandler: $handler ); ``` -------------------------------- ### Generated UsersStorage.php Source: https://github.com/tixlag/spsfw/blob/master/docs/14_spsfw_cli.md Example of a generated storage file for a new chapter, extending PdoStorage. ```php class UsersStorage extends PdoStorage { // TODO: Add storage methods here } ``` -------------------------------- ### Publish Job Immediately Source: https://github.com/tixlag/spsfw/blob/master/docs/11_queue_workes.md Use this method for immediate job publishing, similar to previous versions. No special setup is required beyond having a publisher instance. ```php $publisher->publish($job); ``` -------------------------------- ### Install spsfw via Composer Script Source: https://github.com/tixlag/spsfw/blob/master/docs/14_spsfw_cli.md Integrates spsfw into your project's composer scripts for easy execution. Use `composer run spsfw -- ` to run spsfw commands. ```json { "scripts": { "spsfw": "./vendor/tixlag/php-framework/example/bin/spsfw/spsfw" } } ``` ```bash composer run spsfw -- make:chapter Users ``` -------------------------------- ### Install SpsFW with Composer Source: https://github.com/tixlag/spsfw/blob/master/docs/1_getting_started.md Add SpsFW as a dev-master dependency in your composer.json file and specify a local path or VCS repository. Ensure your autoloader is configured. ```json // composer.json вашего проекта { "require": { "tixlag/php-framework": "dev-master" }, "repositories": [ { "type": "path", "url": "../SpsFW" } ], "autoload": { "psr-4": { "App\": "src/" } } } ``` -------------------------------- ### Start a Single Worker Source: https://github.com/tixlag/spsfw/blob/master/docs/11_queue_workes.md Execute the worker script with the specific worker name as an argument to start a single worker process. This is useful for development and testing. ```bash # Запуск воркера уведомлений php bin/worker.php notification_worker # Запуск воркера импорта php bin/worker.php import_employee_worker # Запуск воркера отчетов php bin/worker.php report_worker ``` -------------------------------- ### Minimal Structure for a New Job and Handler Source: https://github.com/tixlag/spsfw/blob/master/docs/13_queue_reliability_update.md This example demonstrates the minimal structure for a new job extending PayloadQueueJob and its corresponding handler implementing JobHandlerInterface. The #[QueueJob] attribute links the job to its handler. ```php use SpsFW\Core\Queue\PayloadQueueJob; #[QueueJob('my-job', handlerClass: MyJobHandler::class)] class MyJob extends PayloadQueueJob { public function __construct(public readonly string $entityId) {} public function getName(): string { return 'my-job'; } } #[JobHandler('my-job')] class MyJobHandler implements JobHandlerInterface { public function handle(JobInterface $job): JobResult { // бизнес-логика return JobResult::Success; } } ``` -------------------------------- ### Interactive Mode for make:api Source: https://github.com/tixlag/spsfw/blob/master/docs/14_spsfw_cli.md Initiates an interactive prompt for the `make:api` command when no arguments are provided. Guides the user through entering required details. ```bash spsfw make:api # Введите название раздела: Users # Введите маршрут: /api/users/{id} # Введите имя метода: getById # Введите HTTP методы: GET # Добавить шаблонный ответ? (y/N): n ``` -------------------------------- ### Throwing Built-in Exceptions in PHP Source: https://github.com/tixlag/spsfw/blob/master/docs/10_exceptions.md Examples of throwing various framework-provided exceptions to trigger specific HTTP error responses. ```php use SpsFW\Core\Exceptions\NotFoundException; use SpsFW\Core\Exceptions\ForbiddenException; use SpsFW\Core\Exceptions\ConflictException; use SpsFW\Core\Exceptions\TooManyRequestsException; use SpsFW\Core\Exceptions\UnauthorizedException; // 404 — ресурс не найден $deal = $this->dealsStorage->findById($id); if ($deal === null) { throw new NotFoundException("Сделка $id не найдена"); } // 403 — нет прав на действие if ($deal['tenant_id'] !== $currentTenantId) { throw new ForbiddenException(); } // 409 — конфликт (дубликат email) if ($this->usersStorage->existsByEmail($email)) { throw new ConflictException("Пользователь с email $email уже существует"); } // 429 — rate limiting $count = $this->redis->incrWithTtl("rl:login:{$ip}", 60); if ($count > 5) { throw new TooManyRequestsException(); } // 401 — не аутентифицирован if (!$token) { throw new UnauthorizedException(); } ``` -------------------------------- ### Parameterized Access Rule Creation Source: https://github.com/tixlag/spsfw/blob/master/docs/9_access_control.md When creating user access rules, you can assign specific values to rules. This example shows how to set branch IDs for CLIENTS_ACCESS and an empty value for STATS_VIEW. ```php $rules = [ ConsultantRules::CLIENTS_ACCESS => ['branch_ids' => ['uuid-1', 'uuid-2']], ConsultantRules::STATS_VIEW => [], // пустое значение = просто наличие правила ]; ``` -------------------------------- ### Manage systemd Worker Service Source: https://github.com/tixlag/spsfw/blob/master/docs/11_queue_workes.md Use systemctl commands to enable, start, stop, and check the status of the systemd service for your worker. This is essential for managing background processes in production. ```bash # Управление сервисом sudo systemctl enable notification-worker sudo systemctl start notification-worker sudo systemctl status notification-worker ``` -------------------------------- ### Configure Router Caching via Environment Variable Source: https://github.com/tixlag/spsfw/blob/master/docs/15_preload_opcache.md Control router caching using an environment variable. This example sets `useCache` based on the `APP_ENV` variable, disabling cache for 'dev' environments. ```php $useCache = ($_ENV['APP_ENV'] ?? 'dev') !== 'dev'; $router = new Router(useCache: $useCache); ``` -------------------------------- ### Initialize Router and Dispatch Request in index.php Source: https://github.com/tixlag/spsfw/blob/master/docs/1_getting_started.md This is the main entry point for an SPSFW application. It initializes the router, dispatches the incoming request, and sends the response. Ensure bootstrap.php is correctly set up. ```php dispatch(); $response->send(); ``` -------------------------------- ### Control Workers via API Source: https://github.com/tixlag/spsfw/blob/master/docs/11_queue_workes.md Interact with the worker management API to get status, start, stop, or restart individual workers. Requires authentication via a Bearer token. ```bash # Получить статус всех воркеров curl http://your-domain/api/queue/dashboard # Запустить воркера curl -X POST http://your-domain/api/queue/worker/notification_worker/start \ -H "Authorization: Bearer " \ # Остановить воркера curl -X POST http://your-domain/api/queue/worker/notification_worker/stop \ -H "Authorization: Bearer " \ # Перезапустить воркера curl -X POST http://your-domain/api/queue/worker/notification_worker/restart \ -H "Authorization: Bearer " \ ``` -------------------------------- ### Инициализация конфигурации Source: https://github.com/tixlag/spsfw/blob/master/docs/7_configuration.md Метод Config::init() должен вызываться один раз в bootstrap.php. Можно передать массив для добавления собственных секций. ```php Config::init(array $customConfig = []): void ``` ```php Config::init([ 'db_legacy' => [ 'adapter' => $_ENV['LEGACY_DB_ADAPTER'], 'host' => $_ENV['LEGACY_DB_HOST'], 'port' => $_ENV['LEGACY_DB_PORT'], 'user' => $_ENV['LEGACY_DB_USER'], 'password' => $_ENV['LEGACY_DB_PASS'], 'dbname' => $_ENV['LEGACY_DB_NAME'], 'debugMode' => $_ENV['DEBUG_MODE'], ], 'payments' => [ 'api_key' => $_ENV['PAYMENT_API_KEY'], 'sandbox' => $_ENV['PAYMENT_SANDBOX'] === 'true', ], ]); ``` -------------------------------- ### Application Lifecycle Management Source: https://github.com/tixlag/spsfw/blob/master/src/Core/Queue/Controllers/worker-dashboard.html Handles application startup on DOMContentLoaded and resource cleanup on beforeunload. ```javascript // Запуск приложения при загрузке страницы document.addEventListener('DOMContentLoaded', initApp); // Очистка ресурсов при закрытии страницы window.addEventListener('beforeunload', () => { stopAutoRefresh(); }); ``` -------------------------------- ### GET /api/users/{id} Source: https://github.com/tixlag/spsfw/blob/master/docs/2_routing.md Retrieves user information by their unique identifier. ```APIDOC ## GET /api/users/{id} ### Description Retrieves a specific user by their ID. ### Method GET ### Endpoint /api/users/{id} ### Parameters #### Path Parameters - **id** (int) - Required - The unique identifier of the user. ### Response #### Success Response (200) - **id** (int) - User ID - **name** (string) - User name #### Response Example { "id": 1, "name": "John Doe" } ``` -------------------------------- ### SPSFW Typical Workflow Source: https://github.com/tixlag/spsfw/blob/master/docs/14_spsfw_cli.md Standard sequence of commands for project initialization, API route generation, and database migration management. ```bash # 1. Настроить (один раз) spsfw --set-namespace App spsfw --set-root /var/www/my-project # 2. Создать новый раздел spsfw make:chapter Deals # 3. Добавить роуты spsfw make:api Deals '/api/deals' getAll GET spsfw make:api Deals '/api/deals' create POST -v spsfw make:api Deals '/api/deals/{id}' getById GET spsfw make:api Deals '/api/deals/{id}' update PUT spsfw make:api Deals '/api/deals/{id}' delete DELETE # 4. Создать миграцию для сущностей раздела vendor/bin/phinx create CreateDealsTable -c phinx.php # Phinx предложит выбрать путь — выбрать migrations/ внутри Deals/Entities/ # 5. Применить миграцию vendor/bin/phinx migrate -c phinx.php # 6. Прогреть кеш (сброс route/DI кеша) php preload.php ``` -------------------------------- ### GET /api/users/{userId}/posts/{postId} Source: https://github.com/tixlag/spsfw/blob/master/docs/2_routing.md Retrieves a specific post belonging to a specific user. ```APIDOC ## GET /api/users/{userId}/posts/{postId} ### Description Fetches a post identified by postId for a user identified by userId. ### Method GET ### Endpoint /api/users/{userId}/posts/{postId} ### Parameters #### Path Parameters - **userId** (int) - Required - The ID of the user. - **postId** (int) - Required - The ID of the post. ### Response #### Success Response (200) - **user_id** (int) - User ID - **post_id** (int) - Post ID #### Response Example { "user_id": 1, "post_id": 456 } ``` -------------------------------- ### Initialize OutboxPublisher via Factory Source: https://github.com/tixlag/spsfw/blob/master/docs/16_outbox_pattern.md Configure the OutboxPublisher using the QueueClientAndPublisherFactory. Ensure the OutboxStorage is retrieved from the DI container. ```php use SpsFW\Core\Queue\QueueClientAndPublisherFactory; use SpsFW\Core\Queue\Outbox\OutboxStorage; use SpsFW\Core\Storage\PdoStorage; // OutboxStorage берёт соединение из DI/конфига так же, как другие PdoStorage $outboxStorage = $container->get(OutboxStorage::class); $factory = new QueueClientAndPublisherFactory($rabbitConfig); // createWithOutbox — возвращает OutboxPublisher вместо RabbitMQQueuePublisher $publisher = $factory->createWithOutbox( queueName: 'orders', exchange: 'orders.exchange', routingKey: 'order.created', storage: $outboxStorage, autoFlushBatch: 10, // сколько outbox-сообщений дренировать при каждом успешном publish() ); // Через имя воркера: $publisher = $factory->createByWorkerNameWithOutbox('orders_worker', $outboxStorage); ``` -------------------------------- ### Initialize Queue Dashboard Application Source: https://github.com/tixlag/spsfw/blob/master/src/Core/Queue/Controllers/worker-dashboard.html Sets up the UI, loads initial data, and configures background tasks like auto-refresh and health checks. ```javascript async function initApp() { console.log('🚀 Initializing Queue Dashboard...'); // Добавляем дополнительные элементы UI addAutoRefreshToggle(); addExportButton(); // Загружаем начальные данные await loadAvailableJobs(); await refreshDashboard(); // Запускаем автообновление startAutoRefresh(); // Периодически проверяем состояние API setInterval(checkApiHealth, 60000); // каждую минуту // Пытаемся подключить WebSocket // initWebSocket(); console.log('✅ Dashboard initialized successfully'); } ``` -------------------------------- ### OPcache Preload Script for Startup Source: https://github.com/tixlag/spsfw/blob/master/docs/15_preload_opcache.md This script is executed by PHP-FPM at startup when `opcache.preload` is enabled. It compiles essential framework classes and existing cache files into OPcache memory. ```php getFileName()); } } // Компилируем кеши роутов и DI (если уже созданы preload.php) $cacheDir = __DIR__ . '/.cache'; foreach (['compiled_routes.php', 'compiled_di.php'] as $file) { $path = $cacheDir . '/' . $file; if (file_exists($path)) { opcache_compile_file($path); } } ``` -------------------------------- ### Initialize Application Bootstrap Source: https://github.com/tixlag/spsfw/blob/master/docs/1_getting_started.md The bootstrap.php file initializes the SpsFW application by loading environment variables, configuring CORS, initializing the configuration with environment settings, and setting up DI bindings. ```php [ // 'adapter' => $_ENV['LEGACY_DB_ADAPTER'], // 'host' => $_ENV['LEGACY_DB_HOST'], // 'port' => $_ENV['LEGACY_DB_PORT'], // 'user' => $_ENV['LEGACY_DB_USER'], // 'password' => $_ENV['LEGACY_DB_PASS'], // 'dbname' => $_ENV['LEGACY_DB_NAME'], // 'debugMode' => $_ENV['DEBUG_MODE'], // ], ]); // DI-биндинги $diBindings = require __DIR__ . '/config/di_config.php'; Config::setDIBindings($diBindings); ``` -------------------------------- ### Generated API Route in Controller Source: https://github.com/tixlag/spsfw/blob/master/docs/14_spsfw_cli.md Example of a generated route added to a controller file for a specific API endpoint. ```php #[Route('/api/users/{id}', httpMethods: ['GET'])] public function getById(string $id): Response { return Response::json( $this->usersService->getById($id) ); } ``` -------------------------------- ### Run Outbox Migration Source: https://github.com/tixlag/spsfw/blob/master/docs/16_outbox_pattern.md Execute the database migration required for the queue_outbox table. ```bash vendor/bin/phinx migrate ``` -------------------------------- ### Generated Service Method Source: https://github.com/tixlag/spsfw/blob/master/docs/14_spsfw_cli.md Example of a generated method stub added to a service file corresponding to a new API route. ```php public function getById(string $id) { // TODO: Implement getById() method } ``` -------------------------------- ### Router JSON Error Responses Source: https://github.com/tixlag/spsfw/blob/master/docs/10_exceptions.md Examples of the JSON structure returned by the router for handled exceptions versus generic internal errors. ```json { "error": { "status": 404, "uri": "/api/deals/unknown-id", "message": "Сделка unknown-id не найдена", "trace": [] } } ``` ```json { "error": { "status": 500, "message": "Internal server error" } } ``` -------------------------------- ### Пример контроллера с маршрутами Source: https://github.com/tixlag/spsfw/blob/master/docs/2_routing.md Реализация методов контроллера с использованием атрибутов для обработки GET и POST запросов. ```php $id, 'name' => 'John Doe']); } #[Route('/api/users', ['POST'])] public function createUser(): Response { // Логика создания пользователя return Response::created(['id' => 123, 'name' => 'New User']); } } ?> ``` -------------------------------- ### Configure Phinx Migrations Source: https://github.com/tixlag/spsfw/blob/master/docs/0_overview.md Set up Phinx for database migrations by returning the configuration generated by SpsFW\Core\Phinx\PhinxConfigFactory. Ensure autoload is included. ```php clientService->getAll()); } ``` -------------------------------- ### Get Current Authenticated User Source: https://github.com/tixlag/spsfw/blob/master/docs/9_access_control.md Provides methods to retrieve the currently authenticated user object. `Auth::getOrThrow()` throws an exception if no token is present, while `Auth::getOrNull()` returns null. ```php use SpsFW\Core\Auth\Instances\Auth; $user = Auth::getOrThrow(); // throws AuthorizationException если нет токена $user = Auth::getOrNull(); // возвращает null если нет токена $user->uuid // UUID пользователя $user->accessRules // array — правила из JWT ``` -------------------------------- ### Execute Preload Script Source: https://github.com/tixlag/spsfw/blob/master/docs/15_preload_opcache.md Command to run the preload script for cache generation. ```bash php preload.php ``` -------------------------------- ### Метод Config::setDIBindings Source: https://github.com/tixlag/spsfw/blob/master/docs/6_dependency_injection.md Сигнатура метода для регистрации биндингов в конфигурации. ```php Config::setDIBindings(array $bindings) ``` -------------------------------- ### Configure Environment Variables (.env) Source: https://github.com/tixlag/spsfw/blob/master/docs/1_getting_started.md Set up your application's environment variables in the .env file. This includes settings for the environment, HTTP, application details, database, Redis, and JWT authentication. ```dotenv # Среда (используется для загрузки .env.) ENV=dev # HTTP HTTP_SCHEME=https HOST=localhost PORT= # Приложение APP_NAME=my-project APP_VERSION=1.0.0 APP_ENV=dev DEBUG_MODE=true MASTER_PASSWORD=change_me # База данных DB_ADAPTER=pgsql # pgsql | mysql | mariadb DB_HOST=127.0.0.1 DB_PORT=5432 DB_NAME=myapp DB_USER=myapp DB_PASS=secret # Redis REDIS_HOST=redis REDIS_PORT=6379 REDIS_PASSWORD= REDIS_DB=0 REDIS_TIMEOUT=2.0 # Auth / JWT REFRESH_TOKEN_EXPIRES_IN=2592000 JWT_SECRET=change_me_to_long_random_string JWT_EXP_SECONDS=3600 JWT_ALG=HS256 ``` -------------------------------- ### Access Rule Value Retrieval in Controller Source: https://github.com/tixlag/spsfw/blob/master/docs/9_access_control.md In a controller, use AccessChecker::getValue to retrieve the parameterized value associated with an access rule. This example fetches branch IDs for client data retrieval. ```php use SpsFW\Core\Auth\Util\AccessChecker; #[Route('/api/clients', ['GET'])] #[AccessRulesAny([ConsultantRules::CLIENTS_ACCESS])] public function list(): Response { // Возвращает массив из value, или [] если value пустое $accessData = AccessChecker::getValue(ConsultantRules::CLIENTS_ACCESS); $branchIds = $accessData['branch_ids'] ?? null; return Response::json($this->clientService->getAll($branchIds)); } ``` -------------------------------- ### Basic OPcache Configuration Source: https://github.com/tixlag/spsfw/blob/master/docs/15_preload_opcache.md Essential OPcache settings for a production environment. Disable CLI caching and timestamp validation for performance. Adjust memory consumption based on project size. ```ini ; /etc/php/8.3/fpm/conf.d/10-opcache.ini opcache.enable=1 opcache.enable_cli=0 ; CLI не нужен в проде opcache.memory_consumption=256 ; МБ — увеличьте для больших проектов opcache.interned_strings_buffer=16 opcache.max_accelerated_files=20000 opcache.validate_timestamps=0 ; ВАЖНО: в проде отключить, кеш не будет инвалидирован opcache.revalidate_freq=0 opcache.fast_shutdown=1 opcache.jit=tracing ; PHP 8+ JIT (опционально) opcache.jit_buffer_size=128M ``` -------------------------------- ### Create New Chapter Structure Source: https://github.com/tixlag/spsfw/blob/master/docs/14_spsfw_cli.md Generates a standard directory and file structure for a new business section within your project. Supports nested structures. ```bash spsfw make:chapter Users ``` ```bash spsfw make:chapter Products/Catalog ``` ```bash spsfw make:chapter Shop/Cart/Items ``` -------------------------------- ### Publishing a Job to the Queue Source: https://github.com/tixlag/spsfw/blob/master/docs/11_queue_workes.md Use the queue factory to publish a job instance. Ensure the worker configuration is retrieved from the DI container before creating the publisher. ```php // Где угодно в коде - отправляем задачу $queueConfig = $this->workerConfig->getQueueConfig('my_worker'); $job = new MyJob($data); $publisher = $this->queueFactory->create( $queueConfig['queue'], $queueConfig['exchange'], $queueConfig['routing_key'] ); $publisher->publish($job); ``` -------------------------------- ### Send Notification Task to Queue Source: https://github.com/tixlag/spsfw/blob/master/docs/11_queue_workes.md This controller action handles incoming POST requests to send notifications. It retrieves data from the request, gets queue configuration, creates a job, and publishes it to the specified queue using the QueueClientAndPublisherFactory. ```php request->getJsonData(); $queueConfig = $this->workerConfig->getQueueConfig('notification_worker'); // Создаем задачу $job = new SendNotificationJob( email: $data['email'], subject: $data['subject'], message: $data['message'], type: $data['type'] ?? 'email' ); // Создаем publisher для очереди уведомлений $publisher = $this->queueFactory->create( queueName: $queueConfig['queue'], exchange: $queueConfig['exchange'], routingKey: $queueConfig['routing_key'] ); // Отправляем в очередь $publisher->publish($job); return Response::json([ 'success' => true, 'message' => 'Notification queued successfully', 'job_name' => $job->getName() ]); } } ``` -------------------------------- ### Загрузка переменных окружения Source: https://github.com/tixlag/spsfw/blob/master/docs/7_configuration.md Используйте Bootstrap::loadEnv для загрузки конфигурации из .env файлов. Вызывайте метод до инициализации конфигурации. ```php use SpsFW\Core\Bootstrap; Bootstrap::loadEnv(__DIR__ . '/.env'); Bootstrap::loadEnv(__DIR__ . '/.env.' . ($_ENV['ENV'] ?? 'dev')); ``` -------------------------------- ### Настройка нескольких баз данных Source: https://github.com/tixlag/spsfw/blob/master/docs/7_configuration.md Добавление дополнительных соединений с БД через Config::init(). ```php Config::init([ 'db_reporting' => [ 'adapter' => 'pgsql', 'host' => '10.0.0.5', 'port' => 5432, 'user' => 'reporter', 'password' => 'secret', 'dbname' => 'reports', 'debugMode' => false, ], ]); // В Storage: $pdo = $this->getPdo('db_reporting'); ``` -------------------------------- ### Configure Global Rate Limiting Source: https://github.com/tixlag/spsfw/blob/master/docs/17_rate_limiting.md Register the RateLimitMiddleware globally within the router to apply default rate limiting rules across the entire application. ```php use SpsFW\Core\Middleware\RateLimitMiddleware; $router->addGlobalMiddleware(RateLimitMiddleware::class, [ 'windowSeconds' => 60, 'requests' => ['network' => 300, 'fingerprint' => 120, 'user' => 600], 'whitelistRequests' => ['network' => 1500, 'fingerprint' => 400, 'user' => 2000], 'whitelistIps' => [ '10.0.0.10', '10.0.0.11', ], 'keyPrefix' => 'rl:', // Блокировка при превышении лимита (опционально) 'blockDuration' => ['network' => 3600, 'fingerprint' => 1800, 'user' => 3600], ]); ``` -------------------------------- ### Настройка DI-биндингов Source: https://github.com/tixlag/spsfw/blob/master/docs/7_configuration.md Переопределение или добавление DI-биндингов выполняется после вызова Config::init(). ```php Config::setDIBindings([ AuthTokenStorageI::class => RedisTokenStorage::class, LoggerInterface::class => [ 'class' => MonologLogger::class, 'args' => ['/var/log/myapp.log'], ], ]); ``` -------------------------------- ### Initialize Swagger UI with Token Authentication Source: https://github.com/tixlag/spsfw/blob/master/src/Core/Swagger/View/index.html Configures Swagger UI to use a persistent access token, including a custom fetch wrapper to handle 401 unauthorized responses by refreshing the token. ```javascript window.onload = function() { let currentAccessToken = null; // Функция для обновления токена function refreshAccessToken() { return fetch('/api/auth/refresh-tokens', { method: 'POST', credentials: 'include' }) .then(response => { if (!response.ok) { throw new Error('Failed to refresh token'); } const accessToken = response.headers.get('Authorization'); if (accessToken) { currentAccessToken = accessToken.replace('Bearer ', ''); return currentAccessToken; } else { throw new Error('No access token in response'); } }); } // Функция для выполнения запроса с автоматическим обновлением токена function authenticatedRequest(url, options = {}) { options.headers = options.headers || {}; if (currentAccessToken) { options.headers['Authorization'] = 'Bearer ' + currentAccessToken; } return fetch(url, options).then(response => { // Если получили 401, пробуем обновить токен и повторить запрос if (response.status === 401 && currentAccessToken) { return refreshAccessToken().then(newToken => { // Повторяем оригинальный запрос с новым токеном options.headers['Authorization'] = 'Bearer ' + newToken; return fetch(url, options); }); } return response; }); } // Сначала получаем токен refreshAccessToken() .then(token => { // Инициализируем Swagger UI const ui = SwaggerUIBundle({ url: '/swagger/openapi.yaml', dom_id: '#swagger-ui', presets: [ SwaggerUIBundle.presets.apis ], plugins: [ SwaggerUIBundle.plugins.DownloadUrl ], requestInterceptor: function(request) { if (currentAccessToken) { request.headers['Authorization'] = 'Bearer ' + currentAccessToken; } return request; }, // Кастомный fetch для обработки 401 ошибок fetch: function(url, init) { return authenticatedRequest(url, init); } }); }) .catch(error => { console.error('Ошибка инициализации:', error); alert('Не удалось получить доступ к API. Пожалуйста, авторизуйтесь.'); window.location.href = '/public'; }); }; ``` -------------------------------- ### CI/CD Deployment Order Source: https://github.com/tixlag/spsfw/blob/master/docs/15_preload_opcache.md Correct sequence for deploying code, generating caches, and restarting PHP-FPM to ensure optimal performance and cache validity. The order ensures that caches are generated before PHP-FPM reloads and OPcache preloads them. ```bash # 1. Деплой кода git pull origin main composer install --no-dev --optimize-autoloader # 2. Прогрев кеша (сборка route/DI кешей) php preload.php # 3. Перезапуск php-fpm (инвалидирует OPcache, загружает opcache_preload.php) sudo systemctl reload php8.3-fpm # 4. Прогрев OPcache первым запросом (опционально) curl -sf https://myapp.example.com/healthz > /dev/null ``` -------------------------------- ### OPcache Preload Configuration (PHP 7.4+) Source: https://github.com/tixlag/spsfw/blob/master/docs/15_preload_opcache.md Configure OPcache to preload specific classes and cache files upon PHP-FPM startup. This reduces memory usage and speeds up the first request. Ensure `opcache_preload.php` path and user are correctly set. ```ini opcache.preload=/var/www/my-project/opcache_preload.php opcache.preload_user=www-data ``` -------------------------------- ### SPSFW Auxiliary Commands Source: https://github.com/tixlag/spsfw/blob/master/docs/14_spsfw_cli.md Basic utility commands for managing project paths, namespaces, and viewing help information. ```bash spsfw --help # Справка и примеры spsfw --version # Версия утилиты spsfw --show-paths # Текущий корень проекта, target dir и namespace spsfw --set-root # Задать корень проекта spsfw --set-namespace # Задать базовый namespace ``` -------------------------------- ### Конфигурация .env Source: https://github.com/tixlag/spsfw/blob/master/docs/8_database_migrations.md Переменные окружения для подключения к базе данных. ```dotenv DB_ADAPTER=mysql # mysql | pgsql DB_HOST=localhost DB_PORT=3306 DB_NAME=myapp DB_USER=root DB_PASS=secret DB_CHARSET=utf8mb4 APP_ENV=dev ``` -------------------------------- ### Configure DI Container Bindings Source: https://github.com/tixlag/spsfw/blob/master/docs/0_overview.md Define dependency injection mappings using Config::setDIBindings. Supports class strings, object instances, argument arrays, and lazy-loaded callables. ```php // Поддерживаемые форматы биндингов: Config::setDIBindings([ UserServiceI::class => UserService::class, // строка → класс CacheInterface::class => new FileCache('/tmp/cache'), // инстанс HttpClientI::class => ['class' => GuzzleAdapter::class, 'args' => ['https://api.example.com']], // с аргументами RedisClient::class => fn() => RedisClient::getInstance(), // callable (lazy) ]); ``` -------------------------------- ### Implement MiddlewareInterface Source: https://github.com/tixlag/spsfw/blob/master/docs/5_middleware.md The base interface for all middleware components, requiring handle and after methods. ```php interface MiddlewareInterface { public function handle(Request $request): Request; public function after(Response $response): Response; } ``` -------------------------------- ### Configure Row Versioning Source: https://github.com/tixlag/spsfw/blob/master/docs/8_database_migrations.md Use CURRENT_TIMESTAMP and ON UPDATE CURRENT_TIMESTAMP to automatically track record creation and modification times. ```sql created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ``` -------------------------------- ### Project Structure Overview Source: https://github.com/tixlag/spsfw/blob/master/docs/1_getting_started.md This is a typical directory structure for an SpsFW project, outlining the locations for application code, configuration, cache, environment variables, and entry points. ```text my-project/ ├── src/ # Код приложения │ └── Users/ # Пример раздела (chapter) │ ├── Controllers/ │ │ └── UsersController.php │ ├── Services/ │ │ └── UsersService.php │ ├── Storages/ │ │ └── UsersStorage.php │ ├── Entities/ │ │ ├── migrations/ # Phinx-миграции раздела │ │ └── MigrationRequiredClass.php │ ├── DTOs/ │ └── Enums/ ├── config/ │ └── di_config.php # DI-биндинги ├── .cache/ # Кеш роутов и DI (авто, в .gitignore) ├── .env # Переменные окружения ├── .env.dev # Переопределения для dev ├── .env.prod # Переопределения для prod ├── bootstrap.php # Инициализация приложения ├── index.php # Точка входа HTTP └── preload.php # Прогрев кеша (деплой/перезапуск) ```