{"id":484535,"date":"2026-06-22T11:32:52","date_gmt":"2026-06-22T11:32:52","guid":{"rendered":"https:\/\/savepearlharbor.com\/?p=484535"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=484535","title":{"rendered":"\u041a\u0430\u043a \u044f php \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u043f\u0438\u0441\u0430\u043b"},"content":{"rendered":"<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0432\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u044f \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0434\u0438\u0441\u043a\u043b\u0435\u0439\u043c\u0435\u0440. \u041d\u0438\u0436\u0435 \u0434\u043b\u0438\u043d\u043d\u043e\u043f\u043e\u0441\u0442 \u043f\u0440\u043e \u0441\u0430\u043c\u043e\u043f\u0438\u0441\u043d\u044b\u0439 PHP-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a, \u0441 \u043f\u0440\u0438\u043c\u0435\u0440\u0430\u043c\u0438 \u043a\u043e\u0434\u0430 \u0438 \u0435\u0433\u043e \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435\u043c. \u0410\u0432\u0442\u043e\u0440 \u043d\u0435 \u0438\u043d\u0442\u0435\u0440\u043f\u0440\u0430\u0439\u0437-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a, \u043f\u043e \u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u044e \u044f \u044e\u0440\u0438\u0441\u0442, \u0430 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0434\u043b\u044f \u043c\u0435\u043d\u044f \u043f\u0440\u043e\u0441\u0442\u043e \u0445\u043e\u0431\u0431\u0438, \u0442\u043e, \u0447\u0442\u043e \u043c\u0435\u043d\u044f \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442. \u041f\u043e\u0432\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u043d\u0438\u0435 \u0438\u0434\u0435\u0442 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u044f \u0441\u043e\u0431\u0438\u0440\u0430\u043b \u0441\u0432\u043e\u044e \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u0438\u0441\u0445\u043e\u0434\u044f \u0438\u0437 \u0441\u0432\u043e\u0435\u0433\u043e \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043e \u043f\u0440\u0435\u043a\u0440\u0430\u0441\u043d\u043e\u043c \u0438 \u043a \u0447\u0435\u043c\u0443 \u0432 \u0438\u0442\u043e\u0433\u0435 \u043f\u0440\u0438\u0448\u0435\u043b.<\/p>\n<p>\u0411\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u0443 \u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u0439 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u043e\u0442 \u0441\u043b\u043e\u0432\u0430 \u0441\u043e\u0432\u0441\u0435\u043c. \u0411\u0435\u0440\u0435\u0442\u0435 Symfony, Laravel, Spiral, [\u0432\u0430\u0448 \u043b\u044e\u0431\u0438\u043c\u044b\u0439 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a], \u043d\u0443\u0436\u043d\u044b\u0439 \u043d\u0430\u0431\u043e\u0440 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a \u0438 \u0440\u0435\u0448\u0430\u0435\u0442\u0435 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u043e\u0432\u0443\u044e \u0437\u0430\u0434\u0430\u0447\u0443. \u042d\u0442\u043e \u0440\u0430\u0437\u0443\u043c\u043d\u044b\u0439 \u043f\u0443\u0442\u044c.<\/p>\n<p>\u0417\u0430\u0447\u0435\u043c \u0442\u043e\u0433\u0434\u0430 \u044d\u0442\u0438\u043c \u0437\u0430\u043d\u044f\u043b\u0441\u044f \u044f? \u0415\u0441\u043b\u0438 \u043a\u0440\u0430\u0442\u043a\u043e, \u0442\u043e \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043c\u043e\u0433\u0443 \u0438 \u0445\u043e\u0447\u0443, \u0435\u0441\u043b\u0438 \u043d\u0435 \u043e\u0447\u0435\u043d\u044c \u043a\u0440\u0430\u0442\u043a\u043e, \u0442\u043e \u043c\u043d\u0435 \u0431\u044b\u043b\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u0439 PSR-\u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u044b\u0439 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a. \u0412\u0441\u0435 \u043d\u0430\u0447\u0430\u043b\u043e\u0441\u044c \u0435\u0449\u0435 \u0432 \u0441\u0435\u0440\u0435\u0434\u0438\u043d\u0435 \u0434\u0435\u0441\u044f\u0442\u044b\u0445. \u041d\u0430 \u0442\u043e\u0442 \u043c\u043e\u043c\u0435\u043d\u0442 \u043d\u0435\u0434\u0430\u0432\u043d\u043e \u0432\u044b\u0448\u0435\u043b PHP 5.6, \u043f\u0440\u0438\u043d\u044f\u043b\u0438 PSR-7, \u043f\u043e\u0437\u0436\u0435 \u043f\u043e\u044f\u0432\u0438\u043b\u0441\u044f PSR-15, \u0438 \u0441\u0431\u043e\u0440\u043a\u0430 \u0441\u0432\u043e\u0435\u0433\u043e \u0432\u0435\u043b\u043e\u0441\u0438\u043f\u0435\u0434\u0430 \u043d\u0430 \u044d\u0442\u0438\u0445 \u043d\u043e\u0432\u043e\u043c\u043e\u0434\u043d\u044b\u0445 \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0446\u0438\u044f\u0445, \u0441 middleware-\u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d\u043e\u043c, \u043f\u043e\u043a\u0430\u0437\u0430\u043b\u0430\u0441\u044c \u043c\u043d\u0435 \u0432\u0435\u0441\u044c\u043c\u0430 \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u043c \u0438 \u0443\u0432\u043b\u0435\u043a\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u043c \u043f\u0440\u0435\u0434\u043f\u0440\u0438\u044f\u0442\u0438\u0435\u043c.<\/p>\n<p>\u0417\u0430 \u043e\u0441\u043d\u043e\u0432\u0443 \u0431\u044b\u043b\u043e \u0440\u0435\u0448\u0435\u043d\u043e \u0432\u0437\u044f\u0442\u044c <code>nyholm\/psr7<\/code>, <code>PHP-DI<\/code>, \u0434\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u043e\u0442\u0432\u0435\u0442\u0430 \u043f\u0440\u0438\u043a\u0440\u0443\u0442\u0438\u043b <code>laminas\/httphandlerrunner<\/code>, \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0431\u044b\u043b\u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0430 \u0441 \u043e\u0433\u043b\u044f\u0434\u043a\u043e\u0439 \u043d\u0430 \u0442\u043e\u0442 \u0436\u0435 laminas, \u0430 middleware-\u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d, \u0444\u0430\u0431\u0440\u0438\u043a\u0430 \u0434\u043b\u044f \u043d\u0438\u0445, \u043c\u0430\u043f\u0448\u0440\u0443\u0442\u0438\u0437\u0430\u0446\u0438\u044f, app-\u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f, \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438, \u044d\u043a\u0441\u043f\u043e\u0440\u0442 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 (\u0432 \u0442\u043e\u043c \u0447\u0438\u0441\u043b\u0435 \u044d\u043a\u0441\u043f\u043e\u0440\u0442 \u0437\u0430\u043c\u044b\u043a\u0430\u043d\u0438\u0439) \u0438 skeleton-\u043f\u0430\u043a\u0435\u0442 \u0431\u044b\u043b\u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u044b \u0441 \u043d\u0443\u043b\u044f. \u041d\u0430 \u044d\u0442\u043e \u0443\u0448\u043b\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0434\u0432\u0430 \u0438\u043b\u0438 \u0442\u0440\u0438 \u0433\u043e\u0434\u0430, \u0438 \u0433\u0434\u0435-\u0442\u043e \u043a 2020 \u0431\u044b\u043b\u0430 \u0441\u043e\u0431\u0440\u0430\u043d\u0430 \u043f\u0435\u0440\u0432\u0430\u044f \u0440\u0430\u0431\u043e\u0447\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f.<\/p>\n<p>\u041f\u043e\u0442\u043e\u043c \u044f \u0442\u043e \u0437\u0430\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u043b \u043f\u0440\u043e\u0435\u043a\u0442, \u0442\u043e \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u043b\u0441\u044f \u043a \u043d\u0435\u043c\u0443 \u0432\u043d\u043e\u0432\u044c, \u0442\u043e \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u043b \u043a\u0443\u0441\u043a\u0438 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e. \u0412 2025 \u0433\u043e\u0434\u0443 \u0440\u0435\u0448\u0438\u043b \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u043d\u043e\u0439 \u0440\u0430\u0437 \u043f\u0435\u0440\u0435\u0434\u0435\u043b\u0430\u0442\u044c \u0432\u0441\u0435. \u0420\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u043e \u0443\u0441\u0442\u0440\u0435\u043c\u043b\u0435\u043d\u0438\u0435 \u0441\u0438\u043b\u044c\u043d\u043e \u043f\u043e\u043c\u043e\u0433\u043b\u043e \u0440\u0430\u0437\u0432\u0438\u0442\u0438\u0435 \u043a\u043e\u0434\u0438\u043d\u0433-\u0430\u0433\u0435\u043d\u0442\u043e\u0432. \u0421\u043d\u0430\u0447\u0430\u043b\u0430 Claude Code, \u043f\u043e\u0437\u0436\u0435 Codex. \u0411\u043e\u043b\u044c\u0448\u043e\u0439 \u043e\u0431\u044a\u0435\u043c \u043a\u043e\u0434\u043e\u0432\u043e\u0439 \u0431\u0430\u0437\u044b \u0431\u044b\u043b \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u0430\u043d \u0438\u043b\u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043d \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0441 \u043d\u0443\u043b\u044f.<br \/>\u0415\u0441\u043b\u0438 \u043f\u043e\u0441\u043b\u0435 \u043f\u0440\u043e\u0447\u0442\u0435\u043d\u0438\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0442\u044b, \u0434\u043e\u0440\u043e\u0433\u043e\u0439 \u0447\u0438\u0442\u0430\u0442\u0435\u043b\u044c, \u043f\u043e\u0447\u0443\u0432\u0441\u0442\u0432\u043e\u0432\u0430\u043b \u043a\u0430\u043a \u0441\u0432\u0435\u0440\u0431\u0438\u0442 \u0441\u0435\u0434\u0430\u043b\u0438\u0449\u043d\u044b\u0439 \u043d\u0435\u0440\u0432, \u0442\u043e \u043d\u0435 \u0442\u043e\u0440\u043e\u043f\u0438\u0441\u044c \u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u0435 \u0444\u0438 \u0438\u043b\u0438 \u0437\u0430\u043a\u0440\u044b\u0432\u0430\u0442\u044c \u0441\u0442\u0430\u0442\u044c\u044e. \u0422\u0435\u043a\u0441\u0442 \u043d\u0438\u0436\u0435 \u043d\u0435 \u043e \u0432\u0430\u0439\u0431-\u043a\u043e\u0434\u0438\u043d\u0433\u0435 \u0438 \u043d\u0435 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u043b\u0435\u0433\u043a\u043e \u0438 \u043a\u0440\u0443\u0442\u043e \u0432\u043a\u0430\u0442\u0438\u0442\u044c\u0441\u044f \u0432 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u043d\u0435 \u0445\u0443\u0436\u0435 \u0438\u043d\u0442\u0435\u0440\u043f\u0440\u0430\u0439\u0437-\u0443\u0440\u043e\u0432\u043d\u044f, \u043d\u0435 \u0438\u043c\u0435\u044f \u043d\u0438\u043a\u0430\u043a\u043e\u0439 \u044d\u043a\u0441\u043f\u0435\u0440\u0442\u0438\u0437\u044b \u0432 \u0432\u043e\u043f\u0440\u043e\u0441\u0435.<br \/>\u041a\u043e\u0434\u0438\u043d\u0433-\u0430\u0433\u0435\u043d\u0442\u044b \u0445\u043e\u0440\u043e\u0448\u043e \u0440\u0435\u0448\u0430\u044e\u0442 \u0437\u0430\u0434\u0430\u0447\u0443 \u043f\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044e \u0431\u043e\u0439\u043b\u0435\u0440\u043f\u043b\u0435\u0439\u0442\u0430, \u0445\u043e\u0442\u044f, \u0431\u0443\u0434\u0435\u043c \u0447\u0435\u0441\u0442\u043d\u044b, \u043c\u043d\u043e\u0433\u0438\u0435 \u0434\u0440\u0443\u0433\u0438\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 \u043e\u043d\u0438 \u0442\u043e\u0436\u0435 \u0440\u0435\u0448\u0430\u044e\u0442 \u043d\u0430 \u0434\u043e\u0441\u0442\u043e\u0439\u043d\u043e\u043c \u0443\u0440\u043e\u0432\u043d\u0435.<br \/>\u0412 \u043c\u043e\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u044f \u0437\u0430\u043d\u0438\u043c\u0430\u043b\u0441\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u0432, \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043e\u0439, \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435\u043c \u043f\u0440\u043e\u043c\u043f\u0442\u043e\u0432, \u0440\u0435\u0432\u044c\u044e \u0438 \u0432\u044b\u0447\u0438\u0442\u043a\u043e\u0439 README, \u0430 \u043c\u0430\u0448\u0438\u043d\u0430 \u043f\u0438\u0441\u0430\u043b\u0430 \u043a\u043e\u0434, README, \u0442\u0435\u0441\u0442\u044b, \u043d\u0430\u0432\u043e\u0434\u0438\u043b\u0430 \u043d\u0430 \u043d\u0443\u0436\u043d\u044b\u0435 \u043c\u044b\u0441\u043b\u0438, \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u043b\u0430, \u0433\u0434\u0435 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0440\u0435\u0448\u0435\u043d\u0438\u044f.<\/p>\n<p>\u0427\u0442\u043e \u043a\u0430\u0441\u0430\u0435\u0442\u0441\u044f \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0437\u0430\u0434\u0443\u043c\u043a\u0438, \u0442\u043e \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0434\u0435\u043a\u043b\u0430\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u043c \u0438 \u043f\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u043c.<\/p>\n<p>\u041c\u0430\u0440\u0448\u0440\u0443\u0442 \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0440\u044f\u0434\u043e\u043c \u0441 \u043c\u0435\u0442\u043e\u0434\u043e\u043c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430. \u041a\u043e\u043c\u0430\u043d\u0434\u0430 \u0434\u043e\u043b\u0436\u043d\u0430 \u0441\u0430\u043c\u0430 \u0433\u043e\u0432\u043e\u0440\u0438\u0442\u044c, \u043a\u0430\u043a\u0430\u044f \u043f\u043e\u043b\u0438\u0442\u0438\u043a\u0430 \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u043d\u0435\u0439 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f. \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0434\u043e\u043b\u0436\u0435\u043d \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u043f\u043e \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0443. \u0412\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044f \u0434\u043e\u043b\u0436\u043d\u0430 \u0436\u0438\u0442\u044c \u043d\u0430 DTO, \u0430 \u043d\u0435 \u0432 \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u043e\u043c \u0441\u0435\u0440\u0432\u0438\u0441\u0435 \u0441\u0431\u043e\u043a\u0443. \u0415\u0441\u043b\u0438 \u043c\u0435\u0442\u043e\u0434 \u043d\u0443\u0436\u043d\u043e \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c, \u043f\u0440\u0435\u0432\u0440\u0430\u0442\u0438\u0442\u044c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0432 HTTP-\u043e\u0442\u0432\u0435\u0442 \u0438\u043b\u0438 \u043e\u0431\u0435\u0440\u043d\u0443\u0442\u044c \u0432 \u043f\u0430\u0433\u0438\u043d\u0430\u0446\u0438\u044e, \u044d\u0442\u043e \u0442\u043e\u0436\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u0432\u0438\u0434\u043d\u043e \u043d\u0430 \u043c\u0435\u0442\u043e\u0434\u0435.<\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a:<\/p>\n<pre><code class=\"php\">&lt;?phpdeclare(strict_types=1);namespace App\\Post\\Controller;use App\\Post\\Command\\CreatePostCommand;use App\\Post\\Domain\\Post;use App\\Post\\Infrastructure\\Map\\MapCreatePostCommand;use Componenta\\Auth\\Http\\Middleware\\RequireAuthenticationMiddleware;use Componenta\\CQRS\\Command\\CommandBusInterface;use Componenta\\Http\\Router\\Attribute\\Route;use Componenta\\Interceptor\\Http\\Attribute\\Respond;use Componenta\\Interceptor\\Serialization\\Attribute\\Serialize;final class CreatePost{    #[Respond(201, 'application\/json')]    #[Serialize]    #[Route(        name: 'posts.create',        path: '\/posts',        methods: 'POST',        middlewares: [RequireAuthenticationMiddleware::class],        group: 'api',    )]    public function __invoke(        #[MapCreatePostCommand] CreatePostCommand $command,        CommandBusInterface $dispatcher,    ): Post {        return $dispatcher-&gt;dispatch($command)-&gt;result            -&gt;value            -&gt;post;    }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:87px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0437\u043d\u0430\u0435\u0442 \u043f\u0440\u043e HTTP, \u043e\u043d \u043d\u0435 \u043c\u0430\u043f\u0438\u0442 \u0437\u0430\u043f\u0440\u043e\u0441, \u043d\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438 \u043d\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 HTTP-\u043e\u0442\u0432\u0435\u0442. \u041e\u043d \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0433\u043e\u0442\u043e\u0432\u0443\u044e \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u0438 \u043a\u043e\u043c\u0430\u043d\u0434\u043d\u0443\u044e \u0448\u0438\u043d\u0443, \u043f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442. \u0412\u0441\u044e \u043e\u0441\u0442\u0430\u0432\u0448\u0443\u044e\u0441\u044f \u0440\u0430\u0431\u043e\u0442\u0443 \u0434\u0435\u043b\u0430\u0435\u0442 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a. \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u0437\u0430\u043f\u0440\u043e\u0441 \u043f\u043e\u043f\u0430\u0434\u0430\u0435\u0442 \u0432\u043e \u0444\u0440\u043e\u043d\u0442-\u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 <code>public\/index.php<\/code>, \u0442\u0430\u043c \u0437\u0430\u0434\u0430\u0435\u0442\u0441\u044f \u0441\u043a\u043e\u0443\u043f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f HTTP, \u0437\u0430\u0442\u0435\u043c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f <code>config\/config.php<\/code>.  <\/p>\n<pre><code class=\"php\">if (!isset($paths) || !$paths instanceof PathResolverInterface) {    throw new RuntimeException('config\/config.php requires $paths to be a PathResolverInterface instance.');}return new ConfigDefinition(    providers: [        new ComposerPackageConfigProvider($paths-&gt;resolve('config\/componenta-providers.php')),        new AttributeConfigProvider(),        new FileProvider($paths-&gt;resolve('config\/console.php')),        new FileProvider($paths-&gt;resolve('config\/autoload\/{{,*.}global,{,*.}local}.{php,yaml,json}')),    ],    discovery: new DiscoveryDefinition(        directories: ['src'],        exclude: ['Cycle'],    ),);<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><code>ConfigDefinition<\/code> \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442 \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440\u044b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0438 discovery-\u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438. \u0412 skeleton \u043f\u043e\u0441\u043b\u0435 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 discovery \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d \u043d\u0430 <code>src<\/code>: \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0438\u0449\u0435\u0442 \u0442\u0430\u043c \u0444\u0430\u0439\u043b\u044b \u0441 \u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u043d\u044b\u043c\u0438 \u043a\u043b\u0430\u0441\u0441\u0430\u043c\u0438, \u0441\u0442\u0440\u043e\u0438\u0442 \u043a\u0435\u0448 \u0438 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442 \u0435\u0433\u043e \u0432 <code>var\/cache\/dev\/discovery.dev.php<\/code>. \u0415\u0441\u043b\u0438 \u0444\u0430\u0439\u043b\u044b \u0432 \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0435\u043c\u043e\u0439 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 \u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f, \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f \u0441\u043a\u0430\u043d\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0437\u0430\u043d\u043e\u0432\u043e \u0438 \u043a\u0435\u0448 \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e. \u0421\u0430\u043c \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u043d\u0435 \u043f\u0440\u0438\u0432\u044f\u0437\u0430\u043d \u043a \u0438\u043c\u0435\u043d\u0438 <code>src<\/code>: \u043e\u043d \u0441\u043a\u0430\u043d\u0438\u0440\u0443\u0435\u0442 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438, \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u044b\u0435 \u0432 <code>DiscoveryDefinition<\/code>.<\/p>\n<p><code>ComposerPackageConfigProvider<\/code> \u0447\u0438\u0442\u0430\u0435\u0442 <code>config\/componenta-providers.php<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u043f\u0430\u043a\u0435\u0442\u043e\u0432, \u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u043a\u043e\u043d\u0444\u0438\u0433-\u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440\u044b \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a. <code>AttributeConfigProvider<\/code> \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442 \u043f\u043e \u043d\u0430\u0439\u0434\u0435\u043d\u043d\u044b\u043c \u043a\u043b\u0430\u0441\u0441\u0430\u043c, \u0438\u0449\u0435\u0442 <code>#[AsConfig]<\/code> \u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u043f\u0440\u0438\u043a\u043b\u0430\u0434\u043d\u044b\u0435 config provider-\u044b. <code>FileProvider<\/code> \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0444\u0430\u0439\u043b\u044b \u043f\u043e \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u0443. \u0418\u0437 \u044d\u0442\u0438\u0445 \u0431\u043b\u043e\u043a\u043e\u0432 \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u043e\u0431\u0449\u0438\u0439 \u043a\u043e\u043d\u0444\u0438\u0433 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<br \/>\u0414\u043b\u044f \u043f\u0440\u043e\u0434\u0430\u043a\u0448\u0435\u043d \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u043e\u0431\u0449\u0438\u0439 \u043a\u043e\u043d\u0444\u0438\u0433 \u043f\u0438\u0448\u0435\u0442\u0441\u044f \u0432 \u0444\u0430\u0439\u043b \u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u043d, \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440\u044b \u043d\u0435 \u0438\u043d\u0441\u0442\u0430\u043d\u0446\u0438\u0440\u0443\u044e\u0442\u0441\u044f, \u0434\u0438\u0441\u043a\u0430\u0432\u0435\u0440\u0438\u043d\u0433 \u043d\u0435 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442.<\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e \u043a\u0430\u043a \u043a\u043e\u043d\u0444\u0438\u0433 \u0441\u043e\u0431\u0440\u0430\u043d, \u043d\u0430 \u0435\u0433\u043e \u043e\u0441\u043d\u043e\u0432\u0435 \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<p>\u0414\u0430\u043b\u044c\u0448\u0435 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442\u0441\u044f \u0443\u0436\u0435 \u043d\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u0430\u044f, \u0430 \u0440\u0430\u043d\u0442\u0430\u0439\u043c \u0447\u0430\u0441\u0442\u044c. \u0422\u043e\u0447\u043a\u0430 \u0432\u0445\u043e\u0434\u0430 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 <code>Componenta\\App\\run()<\/code> \u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442 \u0442\u0443\u0434\u0430 \u0441\u043a\u043e\u0443\u043f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0414\u043b\u044f HTTP \u044d\u0442\u043e <code>Scope::HTTP<\/code>, \u0434\u043b\u044f \u043a\u043e\u043d\u0441\u043e\u043b\u0438 \u0431\u0443\u0434\u0435\u0442 <code>CLI<\/code>, \u0434\u043b\u044f websocket \u0441\u0435\u0440\u0432\u0435\u0440\u0430 <code>Scope::Websocket<\/code>.<\/p>\n<p>\u0423\u043f\u0440\u043e\u0449\u0435\u043d\u043d\u043e <code>run()<\/code> \u0434\u0435\u043b\u0430\u0435\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u0435\u0449\u0435\u0439:<\/p>\n<pre><code class=\"php\">&lt;?phpfunction run(ScopeInterface $scope, PathResolverInterface $paths): void{    chdir($paths-&gt;baseDir);    $container = require $paths-&gt;resolve('config\/container.php');    $config = $container-&gt;get(Config::class);    $code = Runner::run($scope, new ContainerValue($container, $config));    if ($code !== null) {        exit($code);    }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><code>ContainerValue<\/code> \u043f\u043e \u0441\u0443\u0442\u0438 \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0441\u0430\u0445\u0430\u0440 \u043d\u0430\u0434 PSR-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u043e\u043c. \u041e\u043d \u043d\u0435 \u0437\u0430\u043c\u0435\u043d\u044f\u0435\u0442 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0438 \u043d\u0435 \u0432\u0432\u043e\u0434\u0438\u0442 \u043d\u043e\u0432\u044b\u0439 DI-\u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c. \u042d\u0442\u043e \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0430\u044f \u043e\u0431\u0435\u0440\u0442\u043a\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0434\u0435\u0440\u0436\u0438\u0442 \u0440\u044f\u0434\u043e\u043c \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0438 \u0443\u0436\u0435 \u0441\u043e\u0431\u0440\u0430\u043d\u043d\u044b\u0439 <code>Config<\/code>.<\/p>\n<p>\u0421\u0435\u0439\u0447\u0430\u0441 \u043e\u043d \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0442\u0430\u043a:<\/p>\n<pre><code class=\"php\">&lt;?phpdeclare(strict_types=1);namespace Componenta\\Config;use Componenta\\Config\\Exception\\InvalidContainerValueException;use Psr\\Container\\ContainerInterface;final readonly class ContainerValue implements ContainerInterface{    public Config $config;    public function __construct(        public ContainerInterface $value,        ?Config $config = null,    ) {        $this-&gt;config = $config ?? $this-&gt;resolveConfig();    }    public function has(string $id): bool    {        return $this-&gt;value-&gt;has($id);    }    \/**     * @template T of object     * @param class-string&lt;T&gt;|null $type     * @return ($type is null ? mixed : T)     *\/    public function get(string $id, ?string $type = null): mixed    {        $service = $this-&gt;value-&gt;get($id);        if ($type === null) {            return $service;        }        if (!$service instanceof $type) {            throw InvalidContainerValueException::forService($id, $type, $service);        }        return $service;    }    public function find(string $id, mixed $default = null): mixed    {        if ($this-&gt;value-&gt;has($id)) {            $type = $default instanceof ContainerEntry ? $default-&gt;type : null;            return $this-&gt;get($id, $type);        }        if ($default instanceof ContainerEntry) {            return $default-&gt;resolve($this);        }        if ($default instanceof ConfigEntry) {            return $default-&gt;resolve($this-&gt;config);        }        if ($default instanceof LazyValue) {            return $default-&gt;resolve($this);        }        return $default;    }    private function resolveConfig(): Config    {        if (!$this-&gt;value-&gt;has(Config::class)) {            return new Config([]);        }        return $this-&gt;get(Config::class, Config::class);    }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0417\u0430\u0447\u0435\u043c \u0437\u0434\u0435\u0441\u044c <code>get()<\/code>, \u0435\u0441\u043b\u0438 \u0443 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 \u0443\u0436\u0435 \u0435\u0441\u0442\u044c <code>get()<\/code>? \u0412 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c \u0440\u0430\u0434\u0438 \u0432\u0442\u043e\u0440\u043e\u0433\u043e \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430. \u041e\u0431\u044b\u0447\u043d\u044b\u0439 PSR-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 <code>mixed<\/code>, \u0430 <code>ContainerValue::get(Foo::class, Foo::class)<\/code> \u0441\u0440\u0430\u0437\u0443 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0442\u0438\u043f. \u0415\u0441\u043b\u0438 \u0432 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0435 \u043f\u043e\u0434 \u044d\u0442\u0438\u043c id \u0432\u043d\u0435\u0437\u0430\u043f\u043d\u043e \u043b\u0435\u0436\u0438\u0442 \u043d\u0435 <code>Foo<\/code>, \u043e\u0448\u0438\u0431\u043a\u0430 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043d\u044f\u0442\u043d\u043e\u0439 \u0438 \u0440\u0430\u043d\u043d\u0435\u0439.<\/p>\n<p><code>find()<\/code> \u043d\u0443\u0436\u0435\u043d \u0434\u043b\u044f \u0434\u0440\u0443\u0433\u043e\u0433\u043e \u0441\u043b\u0443\u0447\u0430\u044f: \u0441\u0435\u0440\u0432\u0438\u0441 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u043c. \u0411\u0435\u0437 \u043d\u0435\u0433\u043e \u043a\u043e\u0434 \u0431\u044b\u0441\u0442\u0440\u043e \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u0432 \u043e\u0434\u043d\u043e\u0442\u0438\u043f\u043d\u044b\u0435 \u0432\u0435\u0442\u043a\u0438 <code>has()<\/code> \u043f\u043b\u044e\u0441 <code>get()<\/code> \u043f\u043b\u044e\u0441 fallback. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0435\u0441\u043b\u0438 \u0441\u0435\u0440\u0432\u0438\u0441 \u0435\u0441\u0442\u044c, \u0431\u0435\u0440\u0435\u043c \u0435\u0433\u043e. \u0415\u0441\u043b\u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u043d\u0435\u0442, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e. \u0410 \u0435\u0441\u043b\u0438 fallback \u0437\u0430\u0434\u0430\u043d \u043a\u0430\u043a <code>ContainerEntry<\/code>, <code>ConfigEntry<\/code> \u0438\u043b\u0438 <code>LazyValue<\/code>, \u043e\u043d \u0431\u0443\u0434\u0435\u0442 \u0430\u043a\u043a\u0443\u0440\u0430\u0442\u043d\u043e \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d \u0447\u0435\u0440\u0435\u0437 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0438\u043b\u0438 \u043a\u043e\u043d\u0444\u0438\u0433.<\/p>\n<p>\u0422\u043e \u0435\u0441\u0442\u044c \u0443\u0441\u043b\u043e\u0432\u043d\u043e \u0432\u043c\u0435\u0441\u0442\u043e \u0442\u0430\u043a\u043e\u0433\u043e:<\/p>\n<pre><code class=\"php\">$foo = $container-&gt;has(FooInterface::class)    ? $container-&gt;get(FooInterface::class)    : $container-&gt;get(DefaultFoo::class);<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p> \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0430\u043a:  <\/p>\n<pre><code class=\"php\">$foo = $container-&gt;find(    FooInterface::class,    new ContainerEntry(DefaultFoo::class, FooInterface::class),);<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u042d\u0442\u043e \u043d\u0435 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0446\u0438\u044f, \u0441\u043a\u043e\u0440\u0435\u0435 \u0440\u0430\u0431\u043e\u0447\u0438\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0432\u043d\u0443\u0442\u0440\u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430, \u0433\u0434\u0435 \u0442\u0430\u043a\u0438\u0445 \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0445 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u043c\u043d\u043e\u0433\u043e: \u0444\u0430\u0431\u0440\u0438\u043a\u0438, bootloader-\u044b, \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0435 \u043f\u0430\u043a\u0435\u0442\u044b, \u0440\u0430\u0437\u043d\u044b\u0435 \u0441\u043a\u043e\u0443\u043f\u044b \u0437\u0430\u043f\u0443\u0441\u043a\u0430.<\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e <code>Runner<\/code> \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u0441\u0430\u043c\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043f\u043e\u0434 \u043d\u0443\u0436\u043d\u044b\u0439 \u0441\u043a\u043e\u0443\u043f. \u0412 HTTP  \u044d\u0442\u043e HTTP application, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0443\u043c\u0435\u0435\u0442 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c middleware \u0438 \u0432 \u043a\u043e\u043d\u0446\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c PSR-7 response \u0447\u0435\u0440\u0435\u0437 emitter. \u041f\u043e\u0442\u043e\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043e\u0431\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0432 boot target. \u0414\u043b\u044f HTTP \u044d\u0442\u043e <code>HttpBootTargetInterface<\/code>, \u0443 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0435\u0441\u0442\u044c \u043c\u0435\u0442\u043e\u0434 <code>pipe()<\/code>.<\/p>\n<p>\u0417\u0430\u0442\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f <code>BootContext<\/code>:<\/p>\n<pre><code class=\"php\">&lt;?phpfinal readonly class BootContext{    public function __construct(        public ContainerValue $container,        public ScopeInterface $scope,        public object $target,    ) {}    public function target(string $contract): object    {        \/\/ \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430, \u0447\u0442\u043e target \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u0442\u0435\u043a\u0443\u0449\u0435\u043c\u0443 bootloader-\u0443    }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442\u0441\u044f bootloader-\u0430\u043c. Bootloader \u0432\u0438\u0434\u0438\u0442 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440, \u043a\u043e\u043d\u0444\u0438\u0433, \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u0441\u043a\u043e\u0443\u043f \u0438 boot target, \u043d\u043e \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u043f\u0440\u044f\u043c\u043e\u0433\u043e \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u0437\u0430\u043f\u0443\u0441\u043a\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.  Bootloader \u043c\u043e\u0436\u0435\u0442 \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c middleware, \u043f\u043e\u0434\u043f\u0438\u0441\u0430\u0442\u044c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438, \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c discovery cache, \u043d\u043e \u043d\u0435 \u0434\u043e\u043b\u0436\u0435\u043d \u0438 \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0441\u0430\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c HTTP request loop.<\/p>\n<p>\u0421\u043f\u0438\u0441\u043e\u043a bootloader-\u043e\u0432 \u0431\u0435\u0440\u0435\u0442\u0441\u044f \u0438\u0437 \u043a\u043e\u043d\u0444\u0438\u0433\u0430 \u043f\u043e \u043a\u043b\u044e\u0447\u0443 <code>bootloaders<\/code>. \u041a\u0430\u0436\u0434\u044b\u0439 bootloader \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 <code>supports()<\/code>. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043e\u0434\u0438\u043d \u0438 \u0442\u043e\u0442 \u0436\u0435 \u043a\u043e\u043d\u0444\u0438\u0433 \u043c\u043e\u0436\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c HTTP, CLI \u0438 Websocket bootloader-\u044b, \u0430 \u043d\u0430 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u0435, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u0434\u0445\u043e\u0434\u044f\u0442 \u0442\u0435\u043a\u0443\u0449\u0435\u043c\u0443 \u0441\u043a\u043e\u0443\u043f\u0443.<\/p>\n<p>\u0414\u043b\u044f HTTP \u0444\u043b\u043e\u0443 \u0435\u0441\u0442\u044c \u043a\u0430\u043a \u043c\u0438\u043d\u0438\u043c\u0443\u043c \u0434\u0432\u0430 \u0432\u0430\u0436\u043d\u044b\u0445 bootloader-\u0430.<\/p>\n<p>\u041f\u0435\u0440\u0432\u044b\u0439 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 \u0438\u0437 <code>componenta\/app-http<\/code>. \u041e\u043d \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u0442 <code>config\/pipeline.php<\/code>:<\/p>\n<pre><code class=\"php\">&lt;?php\/** @var \\Componenta\\App\\Boot\\Target\\HttpBootTargetInterface $app *\/$app-&gt;pipe(Componenta\\Error\\Http\\Middleware\\ErrorHandlerMiddleware::class, priority: 100);$app-&gt;pipe(Componenta\\Http\\Middleware\\BodyParsingMiddleware::class, priority: 100);<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p> \u0412\u0442\u043e\u0440\u043e\u0439 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 \u0438\u0437 <code>componenta\/router-app<\/code>. \u041e\u043d \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u0442 middleware \u0440\u043e\u0443\u0442\u0438\u043d\u0433\u0430 \u0441\u0430\u043c, \u0447\u0435\u0440\u0435\u0437 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0439 bootloader:  <\/p>\n<pre><code class=\"php\">&lt;?phpfinal class RoutingBootloader implements BootloaderInterface{    private const int ROUTING_PRIORITY = 50;    public function boot(BootContext $context): void    {        $app = $context-&gt;target(HttpBootTargetInterface::class);        $app-&gt;pipe(MatchRouteMiddleware::class, self::ROUTING_PRIORITY);        $app-&gt;pipe(DispatchRouteMiddleware::class, self::ROUTING_PRIORITY);    }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0422\u043e \u0435\u0441\u0442\u044c <code>MatchRouteMiddleware<\/code> \u0438 <code>DispatchRouteMiddleware<\/code> \u043d\u0435 \u043d\u0430\u0434\u043e \u0440\u0443\u043a\u0430\u043c\u0438 \u043f\u0438\u0441\u0430\u0442\u044c \u0432 <code>config\/pipeline.php<\/code>. \u041e\u043d\u0438 \u043f\u043e\u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f, \u043a\u043e\u0433\u0434\u0430 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d router integration package. \u041f\u0440\u0438\u043e\u0440\u0438\u0442\u0435\u0442\u044b \u0442\u043e\u0436\u0435 \u0432\u0430\u0436\u043d\u044b: middleware \u0441 \u0431\u043e\u043b\u044c\u0448\u0438\u043c \u043f\u0440\u0438\u043e\u0440\u0438\u0442\u0435\u0442\u043e\u043c \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0442\u0441\u044f \u0440\u0430\u043d\u044c\u0448\u0435. \u0412 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0432\u044b\u0448\u0435 error handler \u0438 body parser \u0438\u0434\u0443\u0442 \u0441 \u043f\u0440\u0438\u043e\u0440\u0438\u0442\u0435\u0442\u043e\u043c <code>100<\/code>, \u0440\u043e\u0443\u0442\u0438\u043d\u0433 \u0441 \u043f\u0440\u0438\u043e\u0440\u0438\u0442\u0435\u0442\u043e\u043c <code>50<\/code>. \u0415\u0441\u043b\u0438 \u0443 middleware \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u0439 \u043f\u0440\u0438\u043e\u0440\u0438\u0442\u0435\u0442, \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442\u0441\u044f \u043f\u043e\u0440\u044f\u0434\u043e\u043a \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438.<\/p>\n<p>\u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043d\u0435 \u0437\u043d\u0430\u0435\u0442 \u0434\u0435\u0442\u0430\u043b\u0435\u0439 \u0440\u043e\u0443\u0442\u0435\u0440\u0430. \u041e\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u0434\u0430\u0435\u0442 boot target. HTTP \u043f\u0430\u043a\u0435\u0442 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 pipeline, router \u043f\u0430\u043a\u0435\u0442 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 routing middleware, \u0434\u0440\u0443\u0433\u0438\u0435 \u043f\u0430\u043a\u0435\u0442\u044b \u043c\u043e\u0433\u0443\u0442 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0441\u0432\u043e\u0438 bootloader-\u044b. \u0412 \u0438\u0442\u043e\u0433\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u0438\u0437 \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u0445 \u0447\u0430\u0441\u0442\u0435\u0439, \u043d\u043e \u043f\u043e\u0440\u044f\u0434\u043e\u043a \u043e\u0441\u0442\u0430\u0435\u0442\u0441\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c\u044b\u043c.<\/p>\n<pre><code class=\"php\">&lt;?phpdeclare(strict_types=1);namespace Componenta\\App\\Boot\\Target;use Componenta\\App\\Server\\App;final readonly class HttpBootTarget implements HttpBootTargetInterface{    public function __construct(        private App $app,    ) {}    public function pipe(mixed $middleware, int $priority = 0): void    {        $this-&gt;app-&gt;pipe($middleware, $priority);    }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h3>\u041c\u0430\u0440\u0448\u0440\u0443\u0442 CreatePost<\/h3>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u0432\u0435\u0440\u043d\u0443\u0442\u044c\u0441\u044f \u043a <code>CreatePost<\/code>, \u043d\u043e \u0431\u0435\u0437 \u043f\u043e\u0432\u0442\u043e\u0440\u0435\u043d\u0438\u044f \u043a\u043e\u0434\u0430 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u044b\u043b \u0432\u044b\u0448\u0435. \u0414\u043b\u044f \u043d\u0430\u0441 \u0441\u0435\u0439\u0447\u0430\u0441 \u0432\u0430\u0436\u043d\u044b \u0435\u0433\u043e \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b:<\/p>\n<pre><code class=\"php\">#[Respond(201, 'application\/json')]#[Serialize]#[Route(    'posts.create',    '\/posts',    'POST',    middlewares: [RequireAuthenticationMiddleware::class],    group: 'api',)]<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><code>#[Route]<\/code>, \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0433\u0430\u0434\u0430\u0442\u044c\u0441\u044f, \u0433\u043e\u0432\u043e\u0440\u0438\u0442 \u0440\u043e\u0443\u0442\u0435\u0440\u0443: \u0435\u0441\u0442\u044c \u043c\u0430\u0440\u0448\u0440\u0443\u0442 <code>posts.create<\/code>, \u043f\u0443\u0442\u044c <code>\/posts<\/code>, \u043c\u0435\u0442\u043e\u0434 <code>POST<\/code>, \u0433\u0440\u0443\u043f\u043f\u0430 <code>api<\/code>, \u043f\u043b\u044e\u0441 middleware \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0430.<\/p>\n<p>\u0413\u0440\u0443\u043f\u043f\u0430 <code>api<\/code> \u043d\u0435 \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438. \u0415\u0435 \u043d\u0443\u0436\u043d\u043e \u044f\u0432\u043d\u043e \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432 <code>config\/routes.php<\/code>. \u0414\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0442\u0430\u043a\u043e\u0433\u043e \u043a\u0443\u0441\u043a\u0430:<\/p>\n<pre><code class=\"php\">&lt;?php$api = $routes-&gt;group('api', '\/api\/v1', [    ResponseCacheMiddleware::class,    AuthenticationMiddleware::class,    ProvideCurrentUserMiddleware::class,    TouchSessionMiddleware::class,    RejectBannedUserMiddleware::class,]);<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u043c\u0430\u0440\u0448\u0440\u0443\u0442 \u0438\u0437 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0430 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u043f\u043e\u043b\u043d\u044b\u0439 \u043f\u0443\u0442\u044c <code>\/api\/v1\/posts<\/code>. <code>ResponseCacheMiddleware<\/code> \u0437\u0434\u0435\u0441\u044c \u043d\u0443\u0436\u0435\u043d \u0434\u043b\u044f \u043a\u0435\u0448\u0438\u0440\u0443\u0435\u043c\u044b\u0445 GET-\u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432. \u041d\u0430 <code>POST \/api\/v1\/posts<\/code> \u043e\u043d \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0440\u043e\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441 \u0434\u0430\u043b\u044c\u0448\u0435. \u0415\u0441\u043b\u0438 \u0432 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0435 \u0443\u043a\u0430\u0437\u0430\u043d <code>group: 'api'<\/code>, \u0430 \u0433\u0440\u0443\u043f\u043f\u044b <code>api<\/code> \u0432 <code>config\/routes.php<\/code> \u043d\u0435\u0442, \u044d\u0442\u043e \u043e\u0448\u0438\u0431\u043a\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438, \u0430 \u043d\u0435 \u043f\u043e\u0432\u043e\u0434 \u043c\u043e\u043b\u0447\u0430 \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043c\u0430\u0440\u0448\u0440\u0443\u0442 \u0432 \u043a\u043e\u0440\u0435\u043d\u044c.<\/p>\n<p>\u0412 dev \u0440\u0435\u0436\u0438\u043c\u0435 route listener \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u043d\u0430\u0439\u0434\u0435\u043d\u043d\u044b\u0445 \u043a\u043b\u0430\u0441\u0441\u043e\u0432 \u0438\u0437 class discovery, \u0447\u0438\u0442\u0430\u0435\u0442 <code>#[Route]<\/code> \u0438 \u043d\u0430\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044e \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u043e\u0432. \u0412 production \u043f\u043e\u0441\u043b\u0435 <code>app:build<\/code> \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0431\u0435\u0440\u0435\u0442 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u044b \u0438\u0437 \u0441\u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430 \u043a\u0435\u0448\u0430. \u0412 \u044d\u0442\u043e\u043c \u0440\u0435\u0436\u0438\u043c\u0435 \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440\u044b \u0438 discovery \u043d\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u044e\u0442\u0441\u044f \u043d\u0430 \u043a\u0430\u0436\u0434\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441.<\/p>\n<h3>\u0417\u0430\u043f\u0440\u043e\u0441 \u0434\u043e\u0445\u043e\u0434\u0438\u0442 \u0434\u043e \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430<\/h3>\n<p>\u041a\u043e\u0433\u0434\u0430 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 <code>POST \/api\/v1\/posts<\/code>, HTTP \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441\u043e\u0437\u0434\u0430\u0435\u0442 <code>ServerRequestInterface<\/code> \u0447\u0435\u0440\u0435\u0437 PSR-7 request creator \u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 middleware pipeline.<\/p>\n<p>\u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044e\u0442 middleware \u0441 \u043d\u0430\u0438\u0432\u044b\u0441\u0448\u0438\u043c \u043f\u0440\u0438\u043e\u0440\u0438\u0442\u0435\u0442\u043e\u043c: \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043e\u0448\u0438\u0431\u043e\u043a \u0438 body parser. Body parser \u043f\u0430\u0440\u0441\u0438\u0442 \u0442\u0435\u043b\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430 (\u0435\u0441\u043b\u0438 \u043d\u0443\u0436\u043d\u043e) \u0438 \u043a\u043b\u0430\u0434\u0435\u0442 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0432 <code>$request-&gt;getParsedBody()<\/code>.<\/p>\n<p>\u041f\u043e\u0442\u043e\u043c \u0441\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0440\u043e\u0443\u0442\u0438\u043d\u0433 <code>MatchRouteMiddleware<\/code> \u043d\u0430\u0445\u043e\u0434\u0438\u0442 <code>posts.create<\/code> \u0438 \u043a\u043b\u0430\u0434\u0435\u0442 \u043d\u0430\u0439\u0434\u0435\u043d\u043d\u044b\u0439 \u043c\u0430\u0440\u0448\u0440\u0443\u0442 \u0432 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b psr-7 \u0437\u0430\u043f\u0440\u043e\u0441\u0430. <code>DispatchRouteMiddleware<\/code> \u0431\u0435\u0440\u0435\u0442 route handler \u0438 \u043f\u0440\u043e\u0433\u043e\u043d\u044f\u0435\u0442 middleware \u0433\u0440\u0443\u043f\u043f\u044b <code>api<\/code>, \u0437\u0430\u0442\u0435\u043c middleware \u0441\u0430\u043c\u043e\u0433\u043e \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0430. \u0412 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043f\u0435\u0440\u0435\u0434 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u043e\u043c \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a\u0430\u044f \u0446\u0435\u043f\u043e\u0447\u043a\u0430:<\/p>\n<pre><code>ErrorHandlerMiddleware                    priority 100BodyParsingMiddleware                     priority 100MatchRouteMiddleware                      priority 50DispatchRouteMiddleware                   priority 50  ResponseCacheMiddleware                 group api  AuthenticationMiddleware                group api  ProvideCurrentUserMiddleware            group api  TouchSessionMiddleware                  group api  RejectBannedUserMiddleware              group api  RequireAuthenticationMiddleware         route posts.create  App\\Post\\Controller\\CreatePost::__invoke()<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><code>AuthenticationMiddleware<\/code> \u043f\u0440\u043e\u0431\u0443\u0435\u0442 \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. \u041e\u043d \u0434\u043e\u0441\u0442\u0430\u0435\u0442 auth payload \u0438\u0437 \u0437\u0430\u043f\u0440\u043e\u0441\u0430, \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442 \u0435\u0433\u043e \u0432 authenticator chain \u0438, \u0435\u0441\u043b\u0438 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u043f\u0440\u043e\u0448\u043b\u0430, \u043a\u043b\u0430\u0434\u0435\u0442 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0432 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043f\u043e\u0434 \u043a\u043b\u044e\u0447\u043e\u043c <code>IdentityInterface::class<\/code>. <code>ProvideCurrentUserMiddleware<\/code> \u0443\u0436\u0435 \u0447\u0438\u0442\u0430\u0435\u0442 \u044d\u0442\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0438 \u043d\u0430 \u0432\u0440\u0435\u043c\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442 \u0435\u0433\u043e \u0432 <code>CurrentUserProvider<\/code>, \u0447\u0442\u043e\u0431\u044b \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043c\u043e\u0433\u043b\u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c resolver-\u044b \u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u043e\u043d \u043d\u0443\u0436\u0435\u043d. <code>RequireAuthenticationMiddleware<\/code> \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043d\u0430 \u043d\u0430\u043b\u0438\u0447\u0438\u0435 <code>IdentityInterface::class<\/code>. \u0415\u0441\u043b\u0438 \u0442\u0430\u043c \u043d\u0435\u0442 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f, \u0434\u043e <code>CreatePost<\/code> \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043d\u0435 \u0434\u043e\u0439\u0434\u0435\u0442.<\/p>\n<h3>\u041a\u0430\u043a \u0438\u0437 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u0430<\/h3>\n<p>\u041f\u0435\u0440\u0432\u044b\u0439 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430 \u043f\u043e\u043c\u0435\u0447\u0435\u043d \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u043e\u043c <code>#[MapCreatePostCommand]<\/code>. \u042d\u0442\u043e \u043f\u0440\u0438\u043a\u043b\u0430\u0434\u043d\u043e\u0439 \u043c\u0430\u043f\u043f\u0435\u0440 \u043f\u043e\u0432\u0435\u0440\u0445 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u0447\u043d\u043e\u0433\u043e <code>MapRequestPayload<\/code>:<\/p>\n<pre><code class=\"php\">&lt;?phpdeclare(strict_types=1);namespace App\\Post\\Infrastructure\\Map;use Attribute;use Componenta\\DI\\Attribute\\MapRequestPayload;use Componenta\\Identity\\IdentityInterface;#[Attribute]class MapCreatePostCommand extends MapRequestPayload{    protected array $attributes = [IdentityInterface::class];    protected array $cast = [        'categoryId'        =&gt; '?int',        'isPremium'         =&gt; '?bool',        'commentsEnabled'   =&gt; '?bool',        'allowReactions'    =&gt; '?bool',        'hideAuthor'        =&gt; '?bool',        'previewBlockCount' =&gt; '?int',        'publishedAt'       =&gt; '?datetime',        'commentsOpenFrom'  =&gt; '?datetime',        'commentsClosedAt'  =&gt; '?datetime',    ];    protected(set) array $map = [        IdentityInterface::class =&gt; 'actor',        '?meta'                  =&gt; 'metaTags',    ];}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><code>MapRequestPayload<\/code> \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u0442\u0435\u043b\u0430 \u0438 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u043e\u0432 \u0437\u0430\u043f\u0440\u043e\u0441\u0430, \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u044b\u0445 \u0432 $attributes. \u0412 \u044d\u0442\u043e\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u043a payload \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f <code>IdentityInterface::class<\/code>, \u0442\u043e \u0435\u0441\u0442\u044c \u0430\u043a\u0442\u043e\u0440, \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0434\u043e \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u043b\u043e\u0436\u0438\u043b \u0432 $request <code>AuthenticationMiddleware<\/code>.<\/p>\n<p>\u0417\u0430\u0442\u0435\u043c <code>DispatchRouteMiddleware<\/code> \u0431\u0435\u0440\u0435\u0442 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043c\u0430\u0442\u0447\u0438\u043d\u0433\u0430 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0430. \u0415\u0441\u043b\u0438 \u0443 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0430 \u0435\u0441\u0442\u044c middleware \u0433\u0440\u0443\u043f\u043f\u044b \u0438\u043b\u0438 \u0441\u0430\u043c\u043e\u0433\u043e \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0430, \u043e\u043d \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442 \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d \u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 <code>RouteHandler<\/code> \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u043c \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u043c. \u0415\u0441\u043b\u0438 middleware \u043d\u0435\u0442, \u0432 <code>MiddlewareFactory<\/code> \u0443\u0445\u043e\u0434\u0438\u0442 \u0442\u043e\u043b\u044c\u043a\u043e <code>RouteHandler<\/code>. \u0412 \u0444\u0430\u0431\u0440\u0438\u043a\u0435 middleware \u0435\u0441\u0442\u044c \u0446\u0435\u043f\u043e\u0447\u043a\u0430 \u0440\u0435\u0437\u043e\u043b\u0432\u0435\u0440\u043e\u0432, \u0438 <code>router-app<\/code> \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0442\u0443\u0434\u0430 <code>InterceptedRouteHandlerResolver<\/code>. \u042d\u0442\u043e\u0442 resolver \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0435\u0442 <code>RouteHandler<\/code> \u0432 PSR-15 middleware: \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0447\u0435\u0440\u0435\u0437 callable resolver \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0439 callable \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430, \u043f\u043e\u0442\u043e\u043c \u0437\u0430\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0435\u0442 \u0435\u0433\u043e \u0432 <code>InterceptedRouteHandlerMiddleware<\/code>.<\/p>\n<p><code>InterceptedRouteHandlerMiddleware<\/code> \u0443\u0436\u0435 \u043d\u0435 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e. \u041e\u043d \u0441\u043e\u0437\u0434\u0430\u0435\u0442 <code>CallableContext<\/code>, \u043a\u043b\u0430\u0434\u0435\u0442 \u0442\u0443\u0434\u0430 PSR-7 \u0437\u0430\u043f\u0440\u043e\u0441 \u0438 \u0435\u0433\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a, \u043f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442 context \u0432 HTTP-\u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u0447\u0438\u043a\u043e\u0432. \u042d\u0442\u043e\u0442 \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u0444\u0430\u0431\u0440\u0438\u043a\u043e\u0439 <code>HttpInterceptorPipelineFactory<\/code>. \u041f\u0435\u0440\u0432\u044b\u043c \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u0447\u0438\u043a\u043e\u043c \u0432 \u043d\u0435\u043c \u0441\u0442\u043e\u0438\u0442 <code>ParameterResolvingInterceptor<\/code>, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0440\u0435\u0437\u043e\u043b\u0432\u0438\u043d\u0433 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u043d\u0435 \u0431\u0435\u0440\u0435\u0442\u0441\u044f \u0438\u0437 \u0432\u043e\u0437\u0434\u0443\u0445\u0430: \u044d\u0442\u043e \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043f\u0435\u0440\u0432\u044b\u0439 \u0448\u0430\u0433 \u043f\u0435\u0440\u0435\u0434 \u0432\u044b\u0437\u043e\u0432\u043e\u043c callable.<\/p>\n<p>\u0414\u0430\u043b\u044c\u0448\u0435 <code>ParameterResolvingInterceptor<\/code> \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 <code>ParametersResolver<\/code>. \u0412 \u0446\u0435\u043f\u043e\u0447\u043a\u0435 \u0440\u0435\u0437\u043e\u043b\u0432\u0435\u0440\u043e\u0432 \u0435\u0441\u0442\u044c <code>RequestResolver<\/code> \u0438\u0437 DI-\u043f\u0430\u043a\u0435\u0442\u0430. \u041e\u043d \u0432\u0438\u0434\u0438\u0442 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 <code>#[MapCreatePostCommand] CreatePostCommand $command<\/code>, \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 mapper, \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u043c\u0430\u0441\u0441\u0438\u0432 \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0430 \u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442 \u0435\u0433\u043e \u0432 DI \u0444\u0430\u0431\u0440\u0438\u043a\u0443. \u0410 \u0444\u0430\u0431\u0440\u0438\u043a\u0430 \u0441\u043e\u0437\u0434\u0430\u0435\u0442 <code>CreatePostCommand<\/code> \u043a\u0430\u043a \u043e\u0431\u044b\u0447\u043d\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442, \u0441 \u0443\u0447\u0435\u0442\u043e\u043c \u0442\u0438\u043f\u043e\u0432 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0430 \u0438 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u0430\u0432\u0438\u043b DI.<\/p>\n<p>\u0412\u043d\u0443\u0442\u0440\u0438 mapper-\u0430 \u043f\u043e\u0440\u044f\u0434\u043e\u043a \u0442\u043e\u0436\u0435 \u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439. \u0421\u043d\u0430\u0447\u0430\u043b\u0430, \u0435\u0441\u043b\u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0430 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438, \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442\u0441\u044f \u0441\u044b\u0440\u043e\u0439 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043f\u043e \u043f\u0440\u0430\u0432\u0438\u043b\u0430\u043c DTO. \u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f <code>$map,<\/code> <code>$cast<\/code>, <code>$defaults<\/code>, <code>$sortMap<\/code> \u0438 <code>$exclude<\/code>, \u0435\u0441\u043b\u0438 \u043e\u043d\u0438 \u0437\u0430\u0434\u0430\u043d\u044b.<\/p>\n<p>\u0417\u0430\u043f\u0438\u0441\u044c \u0432\u0438\u0434\u0430 <code>'allowReactions' =&gt; '?bool'<\/code> \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442 null-safe cast: \u0435\u0441\u043b\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 <code>null<\/code>, \u043e\u043d\u043e \u0442\u0430\u043a\u0438\u043c \u0438 \u043e\u0441\u0442\u0430\u043d\u0435\u0442\u0441\u044f, \u0430 \u0435\u0441\u043b\u0438 \u043f\u0440\u0438\u0448\u043b\u043e \u043d\u0435 <code>null<\/code>, mapper \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u0442 \u043f\u0440\u0438\u0432\u0435\u0441\u0442\u0438 \u0435\u0433\u043e \u043a \u0431\u0443\u043b\u0435\u0432\u0443. \u0422\u043e \u0436\u0435 \u0441\u0430\u043c\u043e\u0435 \u0441 <code>'?datetime'<\/code>: \u043f\u0443\u0441\u0442\u043e\u0435 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043d\u0435 \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u0432 \u0434\u0430\u0442\u0443, \u043d\u043e \u043d\u0435\u043f\u0443\u0441\u0442\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430 \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u043a <code>DateTimeImmutable<\/code>. \u042d\u0442\u043e \u0443\u0434\u043e\u0431\u043d\u043e \u0434\u043b\u044f nullable \u043f\u043e\u043b\u0435\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u044b.<\/p>\n<p>\u0427\u0442\u043e \u043a\u0430\u0441\u0430\u0435\u0442\u0441\u044f \u0430\u043a\u0442\u043e\u0440\u0430, \u043e\u043d \u043d\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u043e\u043b\u0435\u043c \u0432\u0445\u043e\u0434\u043d\u043e\u0433\u043e payload, \u0430 \u043f\u043e\u043f\u0430\u0434\u0430\u0435\u0442 \u0432 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043f\u043e\u0441\u043b\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0439 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0438 \u0437\u0430\u0442\u0435\u043c \u043c\u0430\u043f\u0438\u0442\u0441\u044f \u0432 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0430 <code>actor<\/code>. \u0410 \u043f\u043e\u043b\u0435 <code>meta<\/code> \u0438\u0437 payload \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u043b\u043e\u0436\u0438\u0442\u044c \u0432 <code>metaTags<\/code>, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0432\u043d\u0435\u0448\u043d\u0435\u0435 API \u0438 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u044f\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u043d\u0435 \u043e\u0431\u044f\u0437\u0430\u043d\u044b \u043d\u0430\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u043e.<\/p>\n<p>\u0415\u0441\u043b\u0438 \u043d\u0443\u0436\u043d\u043e \u0432\u0437\u044f\u0442\u044c \u043e\u0434\u043d\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0438\u0437 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u043e\u0432 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0431\u0435\u0437 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0433\u043e mapper-\u0430, \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <code>RequestAttribute<\/code>. \u041a\u043b\u044e\u0447 \u043c\u043e\u0436\u043d\u043e \u043d\u0435 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c, \u0435\u0441\u043b\u0438 \u043e\u043d \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u0435\u0442 \u0441 \u0438\u043c\u0435\u043d\u0435\u043c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430:<\/p>\n<pre><code class=\"php\">&lt;?phpuse Componenta\\DI\\Attribute\\RequestAttribute;use Componenta\\Identity\\IdentityInterface;final class ExampleController{    public function __invoke(        #[RequestAttribute] int $postId,        #[RequestAttribute(IdentityInterface::class)] IdentityInterface $identity,    ): array {        return [            'postId' =&gt; $postId,            'identity' =&gt; (string) $identity-&gt;uuid,        ];    }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0412 \u043f\u0435\u0440\u0432\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u043d \u0430\u0442\u0440\u0438\u0431\u0443\u0442 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 <code>postId<\/code>, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u043d\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f <code>$postId<\/code>. \u0412\u043e \u0432\u0442\u043e\u0440\u043e\u043c \u043a\u043b\u044e\u0447 \u043d\u0443\u0436\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u044f\u0432\u043d\u043e, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043b\u0435\u0436\u0438\u0442 \u043f\u043e\u0434 \u043a\u043b\u044e\u0447\u043e\u043c <code>IdentityInterface::class<\/code>, \u0430 \u043d\u0435 \u043f\u043e\u0434 \u0441\u0442\u0440\u043e\u043a\u043e\u0439 <code>identity<\/code>.<br \/>\u041f\u043e\u0434\u043e\u0431\u043d\u044b\u0435 \u0431\u0430\u0437\u043e\u0432\u044b\u0435 \u043c\u0430\u043f\u043f\u0435\u0440\u044b \u0435\u0441\u0442\u044c \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u043f\u043e\u043b\u0435\u0439 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 (\u0441\u0435\u0440\u0432\u0435\u0440\u043d\u044b\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b, \u0437\u0430\u0433\u0440\u0443\u0436\u0435\u043d\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u044b \u0438 \u0442\u0434.).<\/p>\n<h3>\u0410\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f \u0438 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u044b<\/h3>\n<p>\u041a\u043e\u043c\u0430\u043d\u0434\u0430 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u043e\u0441\u0442\u0430 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u0431\u044b\u0447\u043d\u044b\u043c readonly DTO. \u041d\u0430 \u043d\u0435\u0439 \u043b\u0435\u0436\u0430\u0442 \u043f\u0440\u0430\u0432\u0438\u043b\u0430 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 \u0438 policy \u0430\u0442\u0440\u0438\u0431\u0443\u0442:<\/p>\n<pre><code class=\"php\">&lt;?phpdeclare(strict_types=1);namespace App\\Post\\Command;use App\\Post\\Policy\\PostsCreate;use App\\User\\Domain\\User;use Componenta\\Policy\\Actor\\ActorAwareInterface;use Componenta\\Validation\\Attribute\\Validate;use Componenta\\Validation\\Attribute\\When;use DateTimeImmutable;#[PostsCreate]final readonly class CreatePostCommand implements ActorAwareInterface{    public function __construct(        public User $actor,        #[When('status:published', then: 'required|string|length:3,300', else: 'nullable|string|length:3,300')]        public ?string $title = null,        #[When('status:published', then: 'required|array', else: 'nullable|array')]        public ?array $content = null,        #[Validate('nullable|date|after:now,true,5')]        public ?DateTimeImmutable $publishedAt = null,        \/\/ \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u043f\u043e\u043b\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u043e\u043f\u0443\u0449\u0435\u043d\u044b    ) {}}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><code>#[PostsCreate]<\/code> \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u043d\u0435 HTTP middleware. \u042d\u0442\u043e\u0442 \u0430\u0442\u0440\u0438\u0431\u0443\u0442 \u0447\u0438\u0442\u0430\u0435\u0442 <code>Componenta\\CQRS\\Command\\Middleware\\PolicyMiddleware<\/code>, \u0442\u043e \u0435\u0441\u0442\u044c middleware \u043a\u043e\u043c\u0430\u043d\u0434\u043d\u043e\u0439 \u0448\u0438\u043d\u044b. \u041e \u0441\u0430\u043c\u043e\u0439 \u0448\u0438\u043d\u0435 \u0440\u0435\u0447\u044c \u043f\u043e\u0439\u0434\u0435\u0442 \u043d\u0438\u0436\u0435, \u043d\u043e \u0441\u043c\u044b\u0441\u043b \u0437\u0434\u0435\u0441\u044c \u0432\u0430\u0436\u0435\u043d \u0441\u0440\u0430\u0437\u0443: handler \u043d\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u043f\u0440\u0430\u0432\u0430 \u0440\u0443\u043a\u0430\u043c\u0438. \u041a\u043e\u043c\u0430\u043d\u0434\u0430 \u0441\u0430\u043c\u0430 \u0441\u043e\u043e\u0431\u0449\u0430\u0435\u0442, \u043a\u0430\u043a\u0430\u044f \u043f\u043e\u043b\u0438\u0442\u0438\u043a\u0430 \u043a \u043d\u0435\u0439 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0441\u044f. <code>ActorAwareInterface<\/code> \u043d\u0443\u0436\u0435\u043d, \u0447\u0442\u043e\u0431\u044b policy \u0441\u043b\u043e\u0439 \u043c\u043e\u0433 \u0432\u0437\u044f\u0442\u044c \u0430\u043a\u0442\u043e\u0440\u0430 \u0438\u0437 \u043a\u043e\u043c\u0430\u043d\u0434\u044b.<\/p>\n<p><code>#[Validate]<\/code> \u0438 <code>#[When]<\/code> \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0442 \u0432\u0445\u043e\u0434\u043d\u043e\u0439 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043e\u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u043f\u043e\u0441\u0442 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 <code>title<\/code> \u0438 <code>content<\/code>, \u0430 \u0447\u0435\u0440\u043d\u043e\u0432\u0438\u043a \u043c\u043e\u0436\u0435\u0442 \u0436\u0438\u0442\u044c \u0431\u0435\u0437 \u043d\u0438\u0445. \u042d\u0442\u043e \u043d\u0435 \u0441\u043f\u0440\u044f\u0442\u0430\u043d\u043e \u0432 \u0444\u043e\u0440\u043c\u0435 \u0438 \u043d\u0435 \u0440\u0430\u0437\u043c\u0430\u0437\u0430\u043d\u043e \u043f\u043e handler-\u0443. \u041f\u0440\u0430\u0432\u0438\u043b\u043e \u043b\u0435\u0436\u0438\u0442 \u0440\u044f\u0434\u043e\u043c \u0441 \u043f\u043e\u043b\u0435\u043c.<\/p>\n<h3>\u0428\u0438\u043d\u0430 \u043a\u043e\u043c\u0430\u043d\u0434<\/h3>\n<p>\u0412 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0435 \u043e\u0441\u0442\u0430\u0435\u0442\u0441\u044f \u043e\u0434\u043d\u0430 \u0441\u0442\u0440\u043e\u043a\u0430 (\u0444\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e 3):<\/p>\n<pre><code class=\"php\">return $dispatcher-&gt;dispatch($command)-&gt;result    -&gt;value    -&gt;post;<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041a\u043e\u043c\u0430\u043d\u0434\u043d\u0430\u044f \u0448\u0438\u043d\u0430 \u043d\u0430\u0445\u043e\u0434\u0438\u0442 handler \u043f\u043e \u043a\u0430\u0440\u0442\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432. \u0412 dev \u0440\u0435\u0436\u0438\u043c\u0435 \u043a\u0430\u0440\u0442\u0430 \u043d\u0430\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f discovery listener-\u043e\u043c \u043f\u043e <code>#[AsCommandHandler]<\/code>. \u0412 production \u0448\u0438\u043d\u0430 \u0447\u0438\u0442\u0430\u0435\u0442 \u0443\u0436\u0435 \u0441\u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0443\u044e \u043a\u0430\u0440\u0442\u0443.<\/p>\n<p>\u041f\u0435\u0440\u0435\u0434 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442 middleware \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d \u0448\u0438\u043d\u044b. \u0412 \u044d\u0442\u043e\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u043e\u043d\u0438 \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u044b \u0442\u0430\u043a:<\/p>\n<pre><code class=\"php\">\\Componenta\\CQRS\\ConfigKey::COMMAND_MIDDLEWARES =&gt; [    PolicyMiddleware::class,    TransportMiddleware::class,    TransactionMiddleware::class,    EventMiddleware::class,],<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><code>PolicyMiddleware<\/code> \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 <code>#[PostsCreate]<\/code>. <\/p>\n<pre><code class=\"php\">#[\\Attribute(\\Attribute::TARGET_METHOD | \\Attribute::TARGET_CLASS)]final class PostsCreate extends PermissionPolicy{    public function __construct()    {        parent::__construct(PostPermission::CREATE);    }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><code>TransportMiddleware<\/code> \u0440\u0435\u0448\u0430\u0435\u0442, \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e \u0438\u043b\u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u044c. <code>TransactionMiddleware<\/code> \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u0442\u0440\u0430\u043d\u0437\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0441\u0442\u044c. <code>EventMiddleware<\/code> \u0440\u0430\u0441\u0441\u044b\u043b\u0430\u0435\u0442 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u043e\u0433\u043e \u0446\u0438\u043a\u043b\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0441\u043b\u0443\u0448\u0430\u0442\u0435\u043b\u044f\u043c.<\/p>\n<p>\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a <code>CreatePostHandler<\/code> \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u043f\u043e\u0441\u0442 \u0447\u0435\u0440\u0435\u0437 \u0444\u0430\u0431\u0440\u0438\u043a\u0443, \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0435\u0432 \u0438 \u043f\u0440\u0435\u0432\u044c\u044e, \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 \u0430\u0433\u0440\u0435\u0433\u0430\u0442 \u0447\u0435\u0440\u0435\u0437 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 <code>PostResult<\/code>. \u042d\u0442\u043e\u0442 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0432\u0430\u0436\u0435\u043d \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0443. \u0415\u0433\u043e \u0447\u0438\u0442\u0430\u044e\u0442 \u0441\u043b\u0443\u0448\u0430\u0442\u0435\u043b\u0438 \u043a\u043e\u043c\u0430\u043d\u0434\u044b.<\/p>\n<p>\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0441\u043b\u0443\u0448\u0430\u0442\u0435\u043b\u044c \u0432\u0435\u0440\u0441\u0438\u0438 \u043f\u043e\u0434\u043f\u0438\u0441\u0430\u043d \u043d\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u0447\u0435\u0440\u0435\u0437 <code>#[AsCommandListener(command: CreatePostCommand::class)]<\/code> \u0438 \u043f\u043e\u0441\u043b\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 snapshot \u043f\u043e\u0441\u0442\u0430. \u0414\u0440\u0443\u0433\u043e\u0439 \u0441\u043b\u0443\u0448\u0430\u0442\u0435\u043b\u044c \u0441\u043c\u043e\u0442\u0440\u0438\u0442 \u043d\u0430 <code>PostResult-&gt;statusTransition<\/code> \u0438 \u043f\u0438\u0448\u0435\u0442 <code>PostStatusLog<\/code>, \u0435\u0441\u043b\u0438 \u0441\u0442\u0430\u0442\u0443\u0441 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0438\u0437\u043c\u0435\u043d\u0438\u043b\u0441\u044f. \u041e\u0431\u0430 \u0441\u043b\u0443\u0448\u0430\u0442\u0435\u043b\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0442\u0441\u044f \u0432\u043d\u0443\u0442\u0440\u0438  \u043e\u0434\u043d\u043e\u0439 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432\u0435\u0440\u0441\u0438\u044f \u0438 \u0436\u0443\u0440\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u0443\u0441\u0430 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u044e\u0442\u0441\u044f \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u0441\u0430\u043c\u0438\u043c \u043f\u043e\u0441\u0442\u043e\u043c.<\/p>\n<p>\u041f\u043e \u0438\u0442\u043e\u0433\u0443 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442\u0441\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435\u043c \u043f\u043e\u0441\u0442\u0430, \u0432\u0435\u0440\u0441\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0438 \u0436\u0443\u0440\u043d\u0430\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0442\u0441\u044f \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u043d\u0438\u043c(\u043f\u043e\u0441\u043b\u0435), \u043d\u043e \u043d\u0435 \u0440\u0430\u0437\u0434\u0443\u0432\u0430\u044e\u0442 \u0435\u0433\u043e.<\/p>\n<h3>\u041f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u0447\u0438\u043a\u0438 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430<\/h3>\n<p>\u041a\u043e\u0433\u0434\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430, \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 <code>Post<\/code>. \u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u0432\u043a\u043b\u044e\u0447\u0430\u044e\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u0447\u0438\u043a\u0438 \u043c\u0435\u0442\u043e\u0434\u0430.<\/p>\n<p>\u0414\u043b\u044f <code>CreatePost<\/code> \u044d\u0442\u043e:<\/p>\n<pre><code class=\"php\">#[Respond(201, 'application\/json')]#[Serialize]<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><code>AttributeInterceptor<\/code> \u0441\u0442\u0440\u043e\u0438\u0442 \u0446\u0435\u043f\u043e\u0447\u043a\u0443 \u043f\u043e \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0430\u043c \u043c\u0435\u0442\u043e\u0434\u0430. \u0412\u0435\u0440\u0445\u043d\u0438\u0439 \u0430\u0442\u0440\u0438\u0431\u0443\u0442 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0432\u043d\u0435\u0448\u043d\u0438\u043c \u0441\u043b\u043e\u0435\u043c, \u043d\u0438\u0436\u043d\u0438\u0439 \u0431\u043b\u0438\u0436\u0435 \u043a \u043c\u0435\u0442\u043e\u0434\u0443. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0440\u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0442\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430 \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 <code>Serialize<\/code>, \u0437\u0430\u0442\u0435\u043c <code>Respond<\/code>.<\/p>\n<p><code>Serialize<\/code> \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0435\u0442 <code>Post<\/code> \u0432 JSON \u0441\u0442\u0440\u043e\u043a\u0443 \u0447\u0435\u0440\u0435\u0437 serializer (\u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e Symfony serializer) \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. <code>Respond<\/code> \u0437\u0430\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0435\u0442 \u0441\u0442\u0440\u043e\u043a\u0443 \u0432 PSR-7 response \u0441\u043e \u0441\u0442\u0430\u0442\u0443\u0441\u043e\u043c <code>201<\/code> \u0438 content type <code>application\/json<\/code>.<\/p>\n<p>\u041f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u0447\u0438\u043a\u0438 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u0434\u0432\u0443\u043c\u044f \u0441\u043f\u043e\u0441\u043e\u0431\u0430\u043c\u0438. \u041f\u0435\u0440\u0432\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431: \u0430\u0442\u0440\u0438\u0431\u0443\u0442 \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u0435\u0442\u0441\u044f \u043e\u0442 <code>Intercept<\/code> \u0438 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442, \u043a\u0430\u043a\u043e\u0439 interceptor service \u043d\u0443\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c. \u0422\u0430\u043a \u0441\u0434\u0435\u043b\u0430\u043d\u044b <code>Respond<\/code> \u0438 <code>Serialize<\/code>. \u0412\u0442\u043e\u0440\u043e\u0439 \u0441\u043f\u043e\u0441\u043e\u0431: \u0441\u0430\u043c \u0430\u0442\u0440\u0438\u0431\u0443\u0442 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442 <code>InterceptorInterface<\/code>. \u0422\u0430\u043a, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d <code>Paginate<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043c\u043e\u0442\u0440\u0438\u0442 \u043d\u0430 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 handler-\u0430 \u0438, \u0435\u0441\u043b\u0438 \u044d\u0442\u043e <code>PaginatorInterface<\/code>, \u043e\u0431\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0435\u0442 \u0435\u0433\u043e \u0432 <code>ResourcePaginator<\/code> \u0441 \u0441\u0441\u044b\u043b\u043a\u0430\u043c\u0438 \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u0438 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0443\u044e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443.<\/p>\n<h3>\u041f\u043e\u043b\u043d\u0430\u044f \u0446\u0435\u043f\u043e\u0447\u043a\u0430<\/h3>\n<p>\u0415\u0441\u043b\u0438 \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u0432\u0441\u0435 \u0432 \u043e\u0434\u0438\u043d \u043f\u0440\u043e\u0445\u043e\u0434, \u043a\u0430\u0440\u0442\u0438\u043d\u0430 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0442\u0430\u043a:<\/p>\n<figure class=\"full-width \"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/5db\/274\/62f\/5db27462f701ac140a8152fa0847a366.png\" width=\"3000\" height=\"1688\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/5db\/274\/62f\/5db27462f701ac140a8152fa0847a366.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/5db\/274\/62f\/5db27462f701ac140a8152fa0847a366.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<p>\u0412 runtime \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0438 DI-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0443\u0436\u0435 \u0433\u043e\u0442\u043e\u0432\u044b \u0434\u043e boot \u0444\u0430\u0437\u044b. Bootloader-\u044b \u043d\u0435 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044e\u0442 \u0437\u0430\u043f\u0440\u043e\u0441 \u0441\u0430\u043c\u0438. \u041e\u043d\u0438 \u0441\u043e\u0431\u0438\u0440\u0430\u044e\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435: HTTP bootloader \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 pipeline, router bootloader \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 middleware \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0430\u0446\u0438\u0438, \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 bootloader-\u044b \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u044e\u0442 \u043d\u0443\u0436\u043d\u044b\u0435 runtime-\u0441\u0435\u0440\u0432\u0438\u0441\u044b.<\/p>\n<p>\u0414\u0430\u043b\u044c\u0448\u0435 \u0437\u0430\u043f\u0440\u043e\u0441 \u0438\u0434\u0435\u0442 \u043f\u043e \u043e\u0431\u044b\u0447\u043d\u043e\u043c\u0443 PSR-15 \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d\u0443. Body parser \u0433\u043e\u0442\u043e\u0432\u0438\u0442 parsed body, <code>MatchRouteMiddleware<\/code> \u043d\u0430\u0445\u043e\u0434\u0438\u0442 \u043c\u0430\u0440\u0448\u0440\u0443\u0442, <code>DispatchRouteMiddleware<\/code> \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442 route pipe, \u0430 route handler \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 interceptor pipeline. \u0422\u0430\u043c <code>ParameterResolvingInterceptor<\/code> \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0437\u0430\u043f\u0440\u043e\u0441 \u0432 DTO, DI factory \u0441\u043e\u0437\u0434\u0430\u0435\u0442 command \u0438\u043b\u0438 query, \u0430 CQRS-\u0448\u0438\u043d\u0430 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u0434\u043b\u044f \u043d\u0438\u0445 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a. \u041d\u0430 \u0432\u044b\u0445\u043e\u0434\u0435 response-\u0438\u043d\u0442\u0435\u0440\u0446\u0435\u043f\u0442\u043e\u0440\u044b \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0443\u044e\u0442 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0438 \u0441\u043e\u0431\u0438\u0440\u0430\u044e\u0442 HTTP \u043e\u0442\u0432\u0435\u0442.<\/p>\n<p>\u041c\u043d\u0435 \u043d\u0435 \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0434\u0435\u043b\u0430\u0442\u044c \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a, \u0433\u0434\u0435 \u043f\u043e\u043b\u043e\u0432\u0438\u043d\u0430 \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u0441\u043f\u0440\u044f\u0442\u0430\u043d\u0430 \u0432 \u043e\u0434\u043d\u043e\u043c \u0431\u043e\u043b\u044c\u0448\u043e\u043c yaml \u0444\u0430\u0439\u043b\u0435, \u0430 \u0432\u0442\u043e\u0440\u0430\u044f \u043f\u043e\u043b\u043e\u0432\u0438\u043d\u0430 \u0440\u0430\u0437\u043c\u0430\u0437\u0430\u043d\u0430 \u043f\u043e \u0441\u0435\u0440\u0432\u0438\u0441 \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440\u0430\u043c. \u041d\u043e \u0438 \u0440\u0443\u0447\u043d\u0430\u044f \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f \u0432\u0441\u0435\u0433\u043e \u043f\u043e\u0434\u0440\u044f\u0434 \u0442\u043e\u0436\u0435 \u0431\u044b\u0441\u0442\u0440\u043e \u043d\u0430\u0434\u043e\u0435\u0434\u0430\u0435\u0442. \u0412 \u0438\u0442\u043e\u0433\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0441\u044f \u043a\u043e\u043c\u043f\u0440\u043e\u043c\u0438\u0441\u0441: \u0432 dev \u0440\u0435\u0436\u0438\u043c\u0435 \u043f\u0438\u0448\u0435\u0448\u044c \u043a\u043b\u0430\u0441\u0441\u044b \u0438 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b, \u0430 \u0432 production \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043f\u043e \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u0441\u043e\u0431\u0440\u0430\u043d\u043d\u044b\u043c \u043a\u0430\u0440\u0442\u0430\u043c \u0438 \u043a\u0435\u0448\u0430\u043c.<\/p>\n<p>\u0417\u0430 \u044d\u0442\u043e \u0435\u0441\u0442\u044c \u0441\u0432\u043e\u044f \u043f\u043b\u0430\u0442\u0430 \u0432 \u0432\u0438\u0434\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0440\u0435\u0444\u043b\u0435\u043a\u0441\u0438\u0438, \u043d\u043e \u043c\u043d\u0435 \u043a\u0430\u0436\u0435\u0442\u0441\u044f \u044d\u0442\u043e \u0434\u043e\u043f\u0443\u0441\u0442\u0438\u043c\u044b\u0439 \u043a\u043e\u043c\u043f\u0440\u043e\u043c\u0438\u0441\u0441, \u0437\u0430\u0442\u043e \u043a\u043e\u0434 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043a\u0440\u0430\u0441\u0438\u0432\u043e \u0438 \u0434\u0435\u043a\u043b\u0430\u0440\u0430\u0442\u0438\u0432\u043d\u043e.<\/p>\n<p>\u041a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u043d\u0435 \u0437\u043d\u0430\u0435\u0442 \u043e JSON \u0438 response. Handler \u043d\u0435 \u0437\u043d\u0430\u0435\u0442 \u043e HTTP. Policy \u043d\u0435 \u0440\u0430\u0437\u043c\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u043e \u043c\u0435\u0442\u043e\u0434\u0430\u043c. \u0421\u043b\u0443\u0448\u0430\u0442\u0435\u043b\u0438 \u043d\u0435 \u0437\u0430\u0441\u043e\u0440\u044f\u044e\u0442 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0439.<\/p>\n<h3>\u0427\u0442\u043e \u043f\u043e \u0447\u0442\u0435\u043d\u0438\u044e \u0434\u0430\u043d\u043d\u044b\u0445 ?<\/h3>\n<p>\u041d\u0438\u0436\u0435 \u043f\u0440\u0438\u043c\u0435\u0440 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430, \u043c\u0430\u043f\u043f\u0435\u0440\u0430, \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0438 \u0435\u0433\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043f\u043e\u0441\u0442\u043e\u0432.<\/p>\n<pre><code class=\"php\">namespace App\\Post\\Controller;final class GetPublicPosts{    #[Respond(200, 'application\/json')]    #[Paginate]    #[Route('posts.get.public', '\/posts', 'GET', group: 'api')]    public function __invoke(        QueryBusInterface $bus,        #[MapGetPublicPostsQuery] GetPublicPostsQuery $query,    ): mixed {        return $bus-&gt;handle($query);    }}namespace App\\Post\\Infrastructure\\Map;use Componenta\\Cycle\\Filter\\Direction;use Componenta\\DI\\Attribute\\MapQueryString;#[\\Attribute(\\Attribute::TARGET_PARAMETER)]class MapGetPublicPostsQuery extends MapQueryString{    protected array $cast = [        'category'  =&gt; 'csv_int',        'tag'       =&gt; 'csv_int',        'date'      =&gt; '?date_filter',        'isPremium' =&gt; 'bool',        'user'      =&gt; 'int',        'limit'     =&gt; 'int',        'offset'    =&gt; 'int',        'preview'   =&gt; 'csv',    ];    protected array $sortMap = [        'latest'  =&gt; ['published_at' =&gt; Direction::DESC],        'oldest'  =&gt; ['published_at' =&gt; Direction::ASC],        'popular' =&gt; ['view_count'   =&gt; Direction::DESC],    ];}namespace App\\Post\\Query;#[Allow]final readonly class GetPublicPosts implements PaginableInterface, RequiresTotalCountInterface, SearchableInterface, SortableInterface{    \/**     * @param list&lt;int&gt;|null $category     * @param list&lt;int&gt;|null $tag     * @param array{from?: string, to?: string, dates?: list&lt;string&gt;}|null $date     * @param array&lt;non-empty-string, Direction&gt;|null $orderBy     * @param list&lt;string&gt;|null $preview     *\/    public function __construct(        public int $limit = 20,        public int $offset = 0,        public ?int $user = null,        public ?array $category = null,        public ?array $tag = null,        public ?bool $isPremium = null,        public ?string $search = null,        public ?array $date = null,        public ?array $orderBy = null,        public ?string $with = null,        public ?array $preview = null,    ) {}}namespace App\\Post\\Query\\Handler;final readonly class GetPublicPostsHandler{    public function __construct(        private PostFetcherInterface $fetcher,    ) {}    #[AsQueryHandler]    public function __invoke(GetPublicPosts $query): array|Paginator    {        return $this-&gt;fetcher-&gt;listPublic($query);    }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><code>MapGetPublicPostsQuery<\/code> \u0431\u0435\u0440\u0435\u0442 \u0438\u043c\u0435\u043d\u043d\u043e query string, \u0430 \u043d\u0435 \u0442\u0435\u043b\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430. \u0414\u043b\u044f \u0447\u0442\u0435\u043d\u0438\u044f \u044d\u0442\u043e \u043b\u043e\u0433\u0438\u0447\u043d\u043e: \u0432\u043d\u0435\u0448\u043d\u0438\u0439 URL \u043e\u0441\u0442\u0430\u0435\u0442\u0441\u044f \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u043e\u043c \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u0438, \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438 \u0438 \u043f\u0430\u0433\u0438\u043d\u0430\u0446\u0438\u0438. \u041c\u0430\u043f\u043f\u0435\u0440 \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442 \u0432\u0445\u043e\u0434\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043a \u0442\u0438\u043f\u0430\u043c query DTO: <code>limit<\/code>, <code>offset<\/code>, <code>user<\/code>, CSV-\u043f\u043e\u043b\u044f <code>category<\/code>, <code>tag<\/code>, <code>preview<\/code>, \u0434\u0430\u0442\u0443, <code>isPremium<\/code> \u0438 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u044b \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438 <code>latest<\/code>, <code>oldest<\/code>, <code>popular<\/code>.<\/p>\n<p><code>#[Allow]<\/code> \u043d\u0430 <code>GetPublicPosts<\/code> \u043d\u0435 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0441\u044f \u043a \u0440\u043e\u0443\u0442\u0438\u043d\u0433\u0443 \u0438 \u043d\u0435 \u043e\u0442\u043a\u043b\u044e\u0447\u0430\u0435\u0442 policy middleware. \u042d\u0442\u043e \u043e\u0431\u044b\u0447\u043d\u0430\u044f policy \u0434\u043b\u044f CQRS-\u0437\u0430\u043f\u0440\u043e\u0441\u0430. \u0428\u0438\u043d\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043f\u0435\u0440\u0435\u0434 \u0432\u044b\u0437\u043e\u0432\u043e\u043c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 <code>Componenta\\CQRS\\Query\\Middleware\\PolicyMiddleware<\/code>, middleware \u0431\u0435\u0440\u0435\u0442 action id \u0438\u0437 \u043a\u043b\u0430\u0441\u0441\u0430 query, \u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u044d\u0442\u043e <code>App\\Post\\Query\\GetPublicPosts<\/code>, \u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442 \u0435\u0433\u043e \u0432 <code>PolicyEnforcer<\/code>. \u0412 dev \u0440\u0435\u0436\u0438\u043c\u0435 policy provider \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u0430\u0442\u0440\u0438\u0431\u0443\u0442 \u0441 \u043a\u043b\u0430\u0441\u0441\u0430 \u0447\u0435\u0440\u0435\u0437 \u0440\u0435\u0444\u043b\u0435\u043a\u0441\u0438\u044e, \u0432 production \u044d\u0442\u043e \u0431\u0435\u0440\u0435\u0442\u0441\u044f \u0438\u0437 \u0441\u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0439 \u043a\u0430\u0440\u0442\u044b policy. \u0421\u0430\u043c <code>Allow<\/code> \u043e\u0447\u0435\u043d\u044c \u043f\u0440\u043e\u0441\u0442\u043e\u0439: \u043e\u043d \u0432\u0441\u0435\u0433\u0434\u0430 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 <code>true<\/code>.<\/p>\n<p>\u0415\u0441\u043b\u0438 <code>#[Allow]<\/code> \u0443\u0431\u0440\u0430\u0442\u044c \u0438 \u043d\u0435 \u043f\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0434\u0440\u0443\u0433\u0443\u044e policy, \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u043c \u0437\u0430\u043f\u0440\u043e\u0441 \u043e\u0442 \u044d\u0442\u043e\u0433\u043e \u043d\u0435 \u0441\u0442\u0430\u043d\u0435\u0442. <code>PolicyMiddleware<\/code> \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 actor: \u0438\u0437 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 \u0432\u044b\u0437\u043e\u0432\u0430, \u0438\u0437 \u0441\u0430\u043c\u043e\u0433\u043e query, \u0435\u0441\u043b\u0438 \u043e\u043d \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442 <code>ActorAwareInterface<\/code>, \u0438\u043b\u0438 \u0447\u0435\u0440\u0435\u0437 <code>ActorProviderInterface<\/code>. \u0412 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0439 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 <code>componenta\/policy<\/code> \u0435\u0441\u0442\u044c \u0433\u043e\u0441\u0442\u0435\u0432\u043e\u0439 actor provider, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0434\u043b\u044f \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u043e\u0433\u043e \u0447\u0442\u0435\u043d\u0438\u044f actor \u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u043a\u043b\u0430\u0441\u0442\u044c \u0432 DTO. \u041d\u043e policy \u0432\u0441\u0435 \u0440\u0430\u0432\u043d\u043e \u0434\u043e\u043b\u0436\u043d\u0430 \u0431\u044b\u0442\u044c. \u0415\u0441\u043b\u0438 actor \u043d\u0430\u0439\u0434\u0435\u043d, \u0430 policy \u0434\u043b\u044f action id \u043d\u0435\u0442, <code>PolicyEnforcer<\/code> \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u043e\u0442\u043a\u0430\u0436\u0435\u0442 \u0432 \u0434\u043e\u0441\u0442\u0443\u043f\u0435, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e missing policy behavior \u0440\u0430\u0432\u0435\u043d <code>DENY<\/code>. \u0415\u0441\u043b\u0438 \u0443\u0431\u0440\u0430\u0442\u044c \u0438 actor provider, \u0438 actor \u0438\u0437 query\/context, \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0435\u0449\u0435 \u0440\u0430\u043d\u044c\u0448\u0435, \u043d\u0430 \u0440\u0435\u0437\u043e\u043b\u0432\u0438\u043d\u0433\u0435 actor (\u0443\u043f\u0430\u0434\u0435\u0442 \u0441 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u043c). \u041f\u0443\u0431\u043b\u0438\u0447\u043d\u043e\u0441\u0442\u044c \u0434\u043e\u043b\u0436\u043d\u0430 \u0431\u044b\u0442\u044c \u044f\u0432\u043d\u043e\u0439.<\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 policy \u0448\u0438\u043d\u0430 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043d\u0430\u0445\u043e\u0434\u0438\u0442 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043f\u043e \u043a\u0430\u0440\u0442\u0435 <code>#[AsQueryHandler]<\/code> \u0438 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u0435\u0433\u043e \u0447\u0435\u0440\u0435\u0437 callable invoker. \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043d\u0435 \u0441\u0442\u0440\u043e\u0438\u0442 HTTP-\u043e\u0442\u0432\u0435\u0442 \u0438 \u043d\u0435 \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u0430\u0432\u0430\u043c\u0438. \u041e\u043d \u043e\u0442\u0434\u0430\u0435\u0442 DTO \u0432 <code>PostFetcher<\/code>, \u0430 fetcher \u0443\u0436\u0435 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442 \u0444\u0438\u043b\u044c\u0442\u0440\u044b, \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0443 \u0438 \u043f\u0430\u0433\u0438\u043d\u0430\u0446\u0438\u044e \u043a SQL-\u0437\u0430\u043f\u0440\u043e\u0441\u0443. \u0415\u0441\u043b\u0438 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f <code>Paginator<\/code>, \u0430\u0442\u0440\u0438\u0431\u0443\u0442 <code>#[Paginate]<\/code> \u043e\u0431\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0435\u0442 \u0435\u0433\u043e \u0432 \u0440\u0435\u0441\u0443\u0440\u0441 \u0441 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u0438 \u0441\u0441\u044b\u043b\u043a\u0430\u043c\u0438, \u0430 <code>#[Respond]<\/code> \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442 HTTP response.<\/p>\n<h3>\u0427\u0442\u043e \u043f\u043e \u0446\u0438\u0444\u0440\u0430\u043c ?<\/h3>\n<p>\u042f \u0437\u0430\u043c\u0435\u0440\u044f\u043b \u044d\u0442\u043e\u0442 endpoint \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e, \u043d\u0430 PHP 8.4.5 \u0438\u0437 OSPanel. \u0412 PHP \u0431\u044b\u043b \u0432\u043a\u043b\u044e\u0447\u0435\u043d OPcache, JIT \u0431\u044b\u043b \u043e\u0442\u043a\u043b\u044e\u0447\u0435\u043d (<code>opcache.jit=disable)<\/code>, preload \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0441\u044f. Production \u0440\u0435\u0436\u0438\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u043b\u0441\u044f \u0441 <code>APP_ENV=production<\/code>, development \u0440\u0435\u0436\u0438\u043c \u0441 <code>APP_ENV=development<\/code>.<\/p>\n<p>\u041c\u0435\u0442\u043e\u0434\u0438\u043a\u0430 \u043f\u0440\u043e\u0441\u0442\u0430\u044f: 10 \u043f\u0440\u043e\u0433\u0440\u0435\u0432\u043e\u0447\u043d\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432, \u0437\u0430\u0442\u0435\u043c 80 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0438\u0437\u043c\u0435\u0440\u044f\u0435\u043c\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432. \u041a\u043b\u0438\u0435\u043d\u0442 &#8212; PowerShell <code>Invoke-WebRequest -UseBasicParsing<\/code>. \u042f \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u0441\u043c\u043e\u0442\u0440\u0435\u043b \u0434\u0432\u0430 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u044f. \u041f\u0435\u0440\u0432\u044b\u0439 \u0434\u0435\u0440\u0433\u0430\u0435\u0442 \u043e\u0434\u0438\u043d \u0438 \u0442\u043e\u0442 \u0436\u0435 URL \u0438 \u043f\u043e\u043f\u0430\u0434\u0430\u0435\u0442 \u0432 warm HTTP-cache \u0432\u043d\u0443\u0442\u0440\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0412\u0442\u043e\u0440\u043e\u0439 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0439 query-\u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 <code>__bench<\/code>, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u043e\u0439\u0442\u0438 backend path \u0437\u0430\u043d\u043e\u0432\u043e: \u0440\u043e\u0443\u0442\u0438\u043d\u0433, middleware, mapper, CQRS, handler, SQL \u0438 \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e.<\/p>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<td>\n<p align=\"left\">\u0420\u0435\u0436\u0438\u043c<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0421\u0446\u0435\u043d\u0430\u0440\u0438\u0439<\/p>\n<\/td>\n<td>\n<p align=\"left\">p50<\/p>\n<\/td>\n<td>\n<p align=\"left\">p95<\/p>\n<\/td>\n<td>\n<p align=\"left\">min<\/p>\n<\/td>\n<td>\n<p align=\"left\">max<\/p>\n<\/td>\n<td>\n<p align=\"left\">avg<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"> prod <\/p>\n<\/td>\n<td>\n<p align=\"left\"> warm HTTP-cache  <\/p>\n<\/td>\n<td>\n<p align=\"left\"> 107.40 ms  <\/p>\n<\/td>\n<td>\n<p align=\"left\"> 180.27 ms  <\/p>\n<\/td>\n<td>\n<p align=\"left\"> 71.67 ms  <\/p>\n<\/td>\n<td>\n<p align=\"left\"> 227.45 ms  <\/p>\n<\/td>\n<td>\n<p align=\"left\"> 117.11 ms  <\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"> prod<\/p>\n<\/td>\n<td>\n<p align=\"left\"> backend path  <\/p>\n<\/td>\n<td>\n<p align=\"left\"> 152.41 ms  <\/p>\n<\/td>\n<td>\n<p align=\"left\"> 211.62 ms  <\/p>\n<\/td>\n<td>\n<p align=\"left\"> 119.78 ms  <\/p>\n<\/td>\n<td>\n<p align=\"left\"> 236.45 ms  <\/p>\n<\/td>\n<td>\n<p align=\"left\"> 156.48 ms  <\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">dev<\/p>\n<\/td>\n<td>\n<p align=\"left\"> warm HTTP-cache  <\/p>\n<\/td>\n<td>\n<p align=\"left\"> 234.65 ms  <\/p>\n<\/td>\n<td>\n<p align=\"left\"> 324.34 ms  <\/p>\n<\/td>\n<td>\n<p align=\"left\"> 194.49 ms  <\/p>\n<\/td>\n<td>\n<p align=\"left\"> 410.32 ms  <\/p>\n<\/td>\n<td>\n<p align=\"left\"> 248.12 ms  <\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"> dev<\/p>\n<\/td>\n<td>\n<p align=\"left\"> backend path  <\/p>\n<\/td>\n<td>\n<p align=\"left\"> 283.95 ms  <\/p>\n<\/td>\n<td>\n<p align=\"left\"> 369.64 ms  <\/p>\n<\/td>\n<td>\n<p align=\"left\"> 228.81 ms  <\/p>\n<\/td>\n<td>\n<p align=\"left\"> 745.75 ms  <\/p>\n<\/td>\n<td>\n<p align=\"left\"> 296.41 ms  <\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>\u041d\u0430\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u044d\u0442\u043e \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0442\u0435\u0441\u0442 &#8212; \u0441\u0443\u0434\u0438\u0442\u0435 \u0441\u0430\u043c\u0438.<\/p>\n<h3>\u0427\u0442\u043e \u0432 \u0438\u0442\u043e\u0433\u0435 ?<\/h3>\n<p>\u041f\u043e \u0444\u0430\u043a\u0442\u0443 \u0441\u0435\u0439\u0447\u0430\u0441 \u0443 \u043c\u0435\u043d\u044f \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0441\u044f \u0431\u043e\u043b\u0435\u0435-\u043c\u0435\u043d\u0435\u0435 \u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u044b\u0439 \u0441\u043a\u0435\u043b\u0435\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0441 \u043c\u0435\u0441\u0442\u0430\u043c\u0438 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0442\u043e\u0447\u043d\u043e\u0439 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0435\u0439 \u043d\u0430 \u0440\u0443\u0441\u0441\u043a\u043e\u043c \u0438 \u0430\u043d\u0433\u043b\u0438\u0439\u0441\u043a\u043e\u043c \u044f\u0437\u044b\u043a\u0430\u0445, \u0441 \u043d\u0430\u0431\u043e\u0440\u043e\u043c \u0442\u0435\u0441\u0442\u043e\u0432. \u041d\u043e \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044e \u0435\u0449\u0435 \u043d\u0443\u0436\u043d\u043e \u0432\u044b\u0447\u0438\u0442\u0430\u0442\u044c \u0434\u043e \u043a\u043e\u043d\u0446\u0430, \u043f\u043e\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u043d\u0435\u0442\u043e\u0447\u043d\u043e\u0441\u0442\u0438 \u0438 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u044c, \u0442\u0435\u0441\u0442\u044b \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c, \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0434\u0443\u043b\u0438 \u043f\u0440\u0438\u0447\u0435\u0441\u0430\u0442\u044c, \u0447\u0435\u043c \u044f \u0438 \u0437\u0430\u043d\u0438\u043c\u0430\u044e\u0441\u044c \u043f\u043e \u043c\u0435\u0440\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438.<br \/>\u0415\u0441\u043b\u0438 \u043c\u043d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0437\u0430\u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043e\u0432\u0430\u0442\u044c \u0438 \u0435\u0441\u0442\u044c \u0436\u0435\u043b\u0430\u043d\u0438\u0435 \u043f\u043e\u0442\u0440\u043e\u0433\u0430\u0442\u044c \u043c\u043e\u044e \u043f\u043e\u0434\u0435\u043b\u043a\u0443 \u0440\u0443\u043a\u0430\u043c\u0438, \u0442\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u044d\u0442\u043e \u043c\u043e\u0436\u043d\u043e <a href=\"https:\/\/github.com\/componenta\/skeleton\" rel=\"noopener noreferrer nofollow\">\u0437\u0434\u0435\u0441\u044c<\/a>.<\/p>\n<p>\u0415\u0441\u043b\u0438 \u0442\u0435\u043a\u0441\u0442 \u0431\u044b\u043b \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0435\u043d \u0438\u043b\u0438 \u043f\u043e\u043b\u0435\u0437\u0435\u043d \u043c\u043e\u0436\u043d\u043e \u0434\u0430\u0442\u044c \u043e\u0431\u0440\u0430\u0442\u043d\u0443\u044e \u0441\u0432\u044f\u0437\u044c.<\/p>\n<p>\u0417.\u042b. \u0420\u0443\u043a\u0430\u043c\u0438 \u043f\u043e\u043a\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u043b \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0439 \u043f\u043e\u043b\u043d\u043e\u0439 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 (\u043f\u0440\u0435\u0441\u0435\u0442 full), \u043e\u043d \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442.<\/p>\n<\/div>\n<p>\u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/1050456\/\">https:\/\/habr.com\/ru\/articles\/1050456\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0432\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u044f \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0434\u0438\u0441\u043a\u043b\u0435\u0439\u043c\u0435\u0440. \u041d\u0438\u0436\u0435 \u0434\u043b\u0438\u043d\u043d\u043e\u043f\u043e\u0441\u0442 \u043f\u0440\u043e \u0441\u0430\u043c\u043e\u043f\u0438\u0441\u043d\u044b\u0439 PHP-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a, \u0441 \u043f\u0440\u0438\u043c\u0435\u0440\u0430\u043c\u0438 \u043a\u043e\u0434\u0430 \u0438 \u0435\u0433\u043e \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435\u043c. \u0410\u0432\u0442\u043e\u0440 \u043d\u0435 \u0438\u043d\u0442\u0435\u0440\u043f\u0440\u0430\u0439\u0437-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a, \u043f\u043e \u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u044e \u044f \u044e\u0440\u0438\u0441\u0442, \u0430 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0434\u043b\u044f \u043c\u0435\u043d\u044f \u043f\u0440\u043e\u0441\u0442\u043e \u0445\u043e\u0431\u0431\u0438, \u0442\u043e, \u0447\u0442\u043e \u043c\u0435\u043d\u044f \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442. \u041f\u043e\u0432\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u043d\u0438\u0435 \u0438\u0434\u0435\u0442 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u044f \u0441\u043e\u0431\u0438\u0440\u0430\u043b \u0441\u0432\u043e\u044e \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u0438\u0441\u0445\u043e\u0434\u044f \u0438\u0437 \u0441\u0432\u043e\u0435\u0433\u043e \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043e \u043f\u0440\u0435\u043a\u0440\u0430\u0441\u043d\u043e\u043c \u0438 \u043a \u0447\u0435\u043c\u0443 \u0432 \u0438\u0442\u043e\u0433\u0435 \u043f\u0440\u0438\u0448\u0435\u043b.\u0411\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u0443 \u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u0439 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u043e\u0442 \u0441\u043b\u043e\u0432\u0430 \u0441\u043e\u0432\u0441\u0435\u043c. \u0411\u0435\u0440\u0435\u0442\u0435 Symfony, Laravel, Spiral, [\u0432\u0430\u0448 \u043b\u044e\u0431\u0438\u043c\u044b\u0439 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a], \u043d\u0443\u0436\u043d\u044b\u0439 \u043d\u0430\u0431\u043e\u0440 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a \u0438 \u0440\u0435\u0448\u0430\u0435\u0442\u0435 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u043e\u0432\u0443\u044e \u0437\u0430\u0434\u0430\u0447\u0443. \u042d\u0442\u043e \u0440\u0430\u0437\u0443\u043c\u043d\u044b\u0439 \u043f\u0443\u0442\u044c.\u0417\u0430\u0447\u0435\u043c \u0442\u043e\u0433\u0434\u0430 \u044d\u0442\u0438\u043c \u0437\u0430\u043d\u044f\u043b\u0441\u044f \u044f? \u0415\u0441\u043b\u0438 \u043a\u0440\u0430\u0442\u043a\u043e, \u0442\u043e \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043c\u043e\u0433\u0443 \u0438 \u0445\u043e\u0447\u0443, \u0435\u0441\u043b\u0438 \u043d\u0435 \u043e\u0447\u0435\u043d\u044c \u043a\u0440\u0430\u0442\u043a\u043e, \u0442\u043e \u043c\u043d\u0435 \u0431\u044b\u043b\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u0439 PSR-\u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u044b\u0439 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a. \u0412\u0441\u0435 \u043d\u0430\u0447\u0430\u043b\u043e\u0441\u044c \u0435\u0449\u0435 \u0432 \u0441\u0435\u0440\u0435\u0434\u0438\u043d\u0435 \u0434\u0435\u0441\u044f\u0442\u044b\u0445. \u041d\u0430 \u0442\u043e\u0442 \u043c\u043e\u043c\u0435\u043d\u0442 \u043d\u0435\u0434\u0430\u0432\u043d\u043e \u0432\u044b\u0448\u0435\u043b PHP 5.6, \u043f\u0440\u0438\u043d\u044f\u043b\u0438 PSR-7, \u043f\u043e\u0437\u0436\u0435 \u043f\u043e\u044f\u0432\u0438\u043b\u0441\u044f PSR-15, \u0438 \u0441\u0431\u043e\u0440\u043a\u0430 \u0441\u0432\u043e\u0435\u0433\u043e \u0432\u0435\u043b\u043e\u0441\u0438\u043f\u0435\u0434\u0430 \u043d\u0430 \u044d\u0442\u0438\u0445 \u043d\u043e\u0432\u043e\u043c\u043e\u0434\u043d\u044b\u0445 \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0446\u0438\u044f\u0445, \u0441 middleware-\u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d\u043e\u043c, \u043f\u043e\u043a\u0430\u0437\u0430\u043b\u0430\u0441\u044c \u043c\u043d\u0435 \u0432\u0435\u0441\u044c\u043c\u0430 \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u043c \u0438 \u0443\u0432\u043b\u0435\u043a\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u043c \u043f\u0440\u0435\u0434\u043f\u0440\u0438\u044f\u0442\u0438\u0435\u043c.\u0417\u0430 \u043e\u0441\u043d\u043e\u0432\u0443 \u0431\u044b\u043b\u043e \u0440\u0435\u0448\u0435\u043d\u043e \u0432\u0437\u044f\u0442\u044c nyholm\/psr7, PHP-DI, \u0434\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u043e\u0442\u0432\u0435\u0442\u0430 \u043f\u0440\u0438\u043a\u0440\u0443\u0442\u0438\u043b laminas\/httphandlerrunner, \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0431\u044b\u043b\u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0430 \u0441 \u043e\u0433\u043b\u044f\u0434\u043a\u043e\u0439 \u043d\u0430 \u0442\u043e\u0442 \u0436\u0435 laminas, \u0430 middleware-\u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d, \u0444\u0430\u0431\u0440\u0438\u043a\u0430 \u0434\u043b\u044f \u043d\u0438\u0445, \u043c\u0430\u043f\u0448\u0440\u0443\u0442\u0438\u0437\u0430\u0446\u0438\u044f, app-\u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f, \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438, \u044d\u043a\u0441\u043f\u043e\u0440\u0442 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 (\u0432 \u0442\u043e\u043c \u0447\u0438\u0441\u043b\u0435 \u044d\u043a\u0441\u043f\u043e\u0440\u0442 \u0437\u0430\u043c\u044b\u043a\u0430\u043d\u0438\u0439) \u0438 skeleton-\u043f\u0430\u043a\u0435\u0442 \u0431\u044b\u043b\u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u044b \u0441 \u043d\u0443\u043b\u044f. \u041d\u0430 \u044d\u0442\u043e \u0443\u0448\u043b\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0434\u0432\u0430 \u0438\u043b\u0438 \u0442\u0440\u0438 \u0433\u043e\u0434\u0430, \u0438 \u0433\u0434\u0435-\u0442\u043e \u043a 2020 \u0431\u044b\u043b\u0430 \u0441\u043e\u0431\u0440\u0430\u043d\u0430 \u043f\u0435\u0440\u0432\u0430\u044f \u0440\u0430\u0431\u043e\u0447\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f.\u041f\u043e\u0442\u043e\u043c \u044f \u0442\u043e \u0437\u0430\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u043b \u043f\u0440\u043e\u0435\u043a\u0442, \u0442\u043e \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u043b\u0441\u044f \u043a \u043d\u0435\u043c\u0443 \u0432\u043d\u043e\u0432\u044c, \u0442\u043e \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u043b \u043a\u0443\u0441\u043a\u0438 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e. \u0412 2025 \u0433\u043e\u0434\u0443 \u0440\u0435\u0448\u0438\u043b \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u043d\u043e\u0439 \u0440\u0430\u0437 \u043f\u0435\u0440\u0435\u0434\u0435\u043b\u0430\u0442\u044c \u0432\u0441\u0435. \u0420\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u043e \u0443\u0441\u0442\u0440\u0435\u043c\u043b\u0435\u043d\u0438\u0435 \u0441\u0438\u043b\u044c\u043d\u043e \u043f\u043e\u043c\u043e\u0433\u043b\u043e \u0440\u0430\u0437\u0432\u0438\u0442\u0438\u0435 \u043a\u043e\u0434\u0438\u043d\u0433-\u0430\u0433\u0435\u043d\u0442\u043e\u0432. \u0421\u043d\u0430\u0447\u0430\u043b\u0430 Claude Code, \u043f\u043e\u0437\u0436\u0435 Codex. \u0411\u043e\u043b\u044c\u0448\u043e\u0439 \u043e\u0431\u044a\u0435\u043c \u043a\u043e\u0434\u043e\u0432\u043e\u0439 \u0431\u0430\u0437\u044b \u0431\u044b\u043b \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u0430\u043d \u0438\u043b\u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043d \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0441 \u043d\u0443\u043b\u044f.\u0415\u0441\u043b\u0438 \u043f\u043e\u0441\u043b\u0435 \u043f\u0440\u043e\u0447\u0442\u0435\u043d\u0438\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0442\u044b, \u0434\u043e\u0440\u043e\u0433\u043e\u0439 \u0447\u0438\u0442\u0430\u0442\u0435\u043b\u044c, \u043f\u043e\u0447\u0443\u0432\u0441\u0442\u0432\u043e\u0432\u0430\u043b \u043a\u0430\u043a \u0441\u0432\u0435\u0440\u0431\u0438\u0442 \u0441\u0435\u0434\u0430\u043b\u0438\u0449\u043d\u044b\u0439 \u043d\u0435\u0440\u0432, \u0442\u043e \u043d\u0435 \u0442\u043e\u0440\u043e\u043f\u0438\u0441\u044c \u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u0435 \u0444\u0438 \u0438\u043b\u0438 \u0437\u0430\u043a\u0440\u044b\u0432\u0430\u0442\u044c \u0441\u0442\u0430\u0442\u044c\u044e. \u0422\u0435\u043a\u0441\u0442 \u043d\u0438\u0436\u0435 \u043d\u0435 \u043e \u0432\u0430\u0439\u0431-\u043a\u043e\u0434\u0438\u043d\u0433\u0435 \u0438 \u043d\u0435 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u043b\u0435\u0433\u043a\u043e \u0438 \u043a\u0440\u0443\u0442\u043e \u0432\u043a\u0430\u0442\u0438\u0442\u044c\u0441\u044f \u0432 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u043d\u0435 \u0445\u0443\u0436\u0435 \u0438\u043d\u0442\u0435\u0440\u043f\u0440\u0430\u0439\u0437-\u0443\u0440\u043e\u0432\u043d\u044f, \u043d\u0435 \u0438\u043c\u0435\u044f \u043d\u0438\u043a\u0430\u043a\u043e\u0439 \u044d\u043a\u0441\u043f\u0435\u0440\u0442\u0438\u0437\u044b \u0432 \u0432\u043e\u043f\u0440\u043e\u0441\u0435.\u041a\u043e\u0434\u0438\u043d\u0433-\u0430\u0433\u0435\u043d\u0442\u044b \u0445\u043e\u0440\u043e\u0448\u043e \u0440\u0435\u0448\u0430\u044e\u0442 \u0437\u0430\u0434\u0430\u0447\u0443 \u043f\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044e \u0431\u043e\u0439\u043b\u0435\u0440\u043f\u043b\u0435\u0439\u0442\u0430, \u0445\u043e\u0442\u044f, \u0431\u0443\u0434\u0435\u043c \u0447\u0435\u0441\u0442\u043d\u044b, \u043c\u043d\u043e\u0433\u0438\u0435 \u0434\u0440\u0443\u0433\u0438\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 \u043e\u043d\u0438 \u0442\u043e\u0436\u0435 \u0440\u0435\u0448\u0430\u044e\u0442 \u043d\u0430 \u0434\u043e\u0441\u0442\u043e\u0439\u043d\u043e\u043c \u0443\u0440\u043e\u0432\u043d\u0435.\u0412 \u043c\u043e\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u044f \u0437\u0430\u043d\u0438\u043c\u0430\u043b\u0441\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u0432, \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043e\u0439, \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435\u043c \u043f\u0440\u043e\u043c\u043f\u0442\u043e\u0432, \u0440\u0435\u0432\u044c\u044e \u0438 \u0432\u044b\u0447\u0438\u0442\u043a\u043e\u0439 README, \u0430 \u043c\u0430\u0448\u0438\u043d\u0430 \u043f\u0438\u0441\u0430\u043b\u0430 \u043a\u043e\u0434, README, \u0442\u0435\u0441\u0442\u044b, \u043d\u0430\u0432\u043e\u0434\u0438\u043b\u0430 \u043d\u0430 \u043d\u0443\u0436\u043d\u044b\u0435 \u043c\u044b\u0441\u043b\u0438, \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u043b\u0430, \u0433\u0434\u0435 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0440\u0435\u0448\u0435\u043d\u0438\u044f.\u0427\u0442\u043e \u043a\u0430\u0441\u0430\u0435\u0442\u0441\u044f \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0437\u0430\u0434\u0443\u043c\u043a\u0438, \u0442\u043e \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0434\u0435\u043a\u043b\u0430\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u043c \u0438 \u043f\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u043c.\u041c\u0430\u0440\u0448\u0440\u0443\u0442 \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0440\u044f\u0434\u043e\u043c \u0441 \u043c\u0435\u0442\u043e\u0434\u043e\u043c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430. \u041a\u043e\u043c\u0430\u043d\u0434\u0430 \u0434\u043e\u043b\u0436\u043d\u0430 \u0441\u0430\u043c\u0430 \u0433\u043e\u0432\u043e\u0440\u0438\u0442\u044c, \u043a\u0430\u043a\u0430\u044f \u043f\u043e\u043b\u0438\u0442\u0438\u043a\u0430 \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u043d\u0435\u0439 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f. \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0434\u043e\u043b\u0436\u0435\u043d \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u043f\u043e \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0443. \u0412\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044f \u0434\u043e\u043b\u0436\u043d\u0430 \u0436\u0438\u0442\u044c \u043d\u0430 DTO, \u0430 \u043d\u0435 \u0432 \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u043e\u043c \u0441\u0435\u0440\u0432\u0438\u0441\u0435 \u0441\u0431\u043e\u043a\u0443. \u0415\u0441\u043b\u0438 \u043c\u0435\u0442\u043e\u0434 \u043d\u0443\u0436\u043d\u043e \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c, \u043f\u0440\u0435\u0432\u0440\u0430\u0442\u0438\u0442\u044c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0432 HTTP-\u043e\u0442\u0432\u0435\u0442 \u0438\u043b\u0438 \u043e\u0431\u0435\u0440\u043d\u0443\u0442\u044c \u0432 \u043f\u0430\u0433\u0438\u043d\u0430\u0446\u0438\u044e, \u044d\u0442\u043e \u0442\u043e\u0436\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u0432\u0438\u0434\u043d\u043e \u043d\u0430 \u043c\u0435\u0442\u043e\u0434\u0435.\u041f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a:&lt;?phpdeclare(strict_types=1);namespace App\\Post\\Controller;use App\\Post\\Command\\CreatePostCommand;use App\\Post\\Domain\\Post;use App\\Post\\Infrastructure\\Map\\MapCreatePostCommand;use Componenta\\Auth\\Http\\Middleware\\RequireAuthenticationMiddleware;use Componenta\\CQRS\\Command\\CommandBusInterface;use Componenta\\Http\\Router\\Attribute\\Route;use Componenta\\Interceptor\\Http\\Attribute\\Respond;use Componenta\\Interceptor\\Serialization\\Attribute\\Serialize;final class CreatePost{    #[Respond(201, &#8216;application\/json&#8217;)]    #[Serialize]    #[Route(        name: &#8216;posts.create&#8217;,        path: &#8216;\/posts&#8217;,        methods: &#8216;POST&#8217;,        middlewares: [RequireAuthenticationMiddleware::class],        group: &#8216;api&#8217;,    )]    public function __invoke(        #[MapCreatePostCommand] CreatePostCommand $command,        CommandBusInterface $dispatcher,    ): Post {        return $dispatcher-&gt;dispatch($command)-&gt;result            -&gt;value            -&gt;post;    }}\u0417\u0434\u0435\u0441\u044c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0437\u043d\u0430\u0435\u0442 \u043f\u0440\u043e HTTP, \u043e\u043d \u043d\u0435 \u043c\u0430\u043f\u0438\u0442 \u0437\u0430\u043f\u0440\u043e\u0441, \u043d\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438 \u043d\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 HTTP-\u043e\u0442\u0432\u0435\u0442. \u041e\u043d \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0433\u043e\u0442\u043e\u0432\u0443\u044e \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u0438 \u043a\u043e\u043c\u0430\u043d\u0434\u043d\u0443\u044e \u0448\u0438\u043d\u0443, \u043f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442. \u0412\u0441\u044e \u043e\u0441\u0442\u0430\u0432\u0448\u0443\u044e\u0441\u044f \u0440\u0430\u0431\u043e\u0442\u0443 \u0434\u0435\u043b\u0430\u0435\u0442 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a. \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u0437\u0430\u043f\u0440\u043e\u0441 \u043f\u043e\u043f\u0430\u0434\u0430\u0435\u0442 \u0432\u043e \u0444\u0440\u043e\u043d\u0442-\u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 public\/index.php, \u0442\u0430\u043c \u0437\u0430\u0434\u0430\u0435\u0442\u0441\u044f \u0441\u043a\u043e\u0443\u043f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f HTTP, \u0437\u0430\u0442\u0435\u043c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f config\/config.php.  if (!isset($paths) || !$paths instanceof PathResolverInterface) {    throw new RuntimeException(&#8216;config\/config.php requires $paths to be a PathResolverInterface instance.&#8217;);}return new ConfigDefinition(    providers: [        new ComposerPackageConfigProvider($paths-&gt;resolve(&#8216;config\/componenta-providers.php&#8217;)),        new AttributeConfigProvider(),        new FileProvider($paths-&gt;resolve(&#8216;config\/console.php&#8217;)),        new FileProvider($paths-&gt;resolve(&#8216;config\/autoload\/{{,*.}global,{,*.}local}.{php,yaml,json}&#8217;)),    ],    discovery: new DiscoveryDefinition(        directories: [&#8216;src&#8217;],        exclude: [&#8216;Cycle&#8217;],    ),);ConfigDefinition \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442 \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440\u044b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0438 discovery-\u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438. \u0412 skeleton \u043f\u043e\u0441\u043b\u0435 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 discovery \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d \u043d\u0430 src: \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0438\u0449\u0435\u0442 \u0442\u0430\u043c \u0444\u0430\u0439\u043b\u044b \u0441 \u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u043d\u044b\u043c\u0438 \u043a\u043b\u0430\u0441\u0441\u0430\u043c\u0438, \u0441\u0442\u0440\u043e\u0438\u0442 \u043a\u0435\u0448 \u0438 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442 \u0435\u0433\u043e \u0432 var\/cache\/dev\/discovery.dev.php. \u0415\u0441\u043b\u0438 \u0444\u0430\u0439\u043b\u044b \u0432 \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0435\u043c\u043e\u0439 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 \u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f, \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f \u0441\u043a\u0430\u043d\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0437\u0430\u043d\u043e\u0432\u043e \u0438 \u043a\u0435\u0448 \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e. \u0421\u0430\u043c \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u043d\u0435 \u043f\u0440\u0438\u0432\u044f\u0437\u0430\u043d \u043a \u0438\u043c\u0435\u043d\u0438 src: \u043e\u043d \u0441\u043a\u0430\u043d\u0438\u0440\u0443\u0435\u0442 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438, \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u044b\u0435 \u0432 DiscoveryDefinition.ComposerPackageConfigProvider \u0447\u0438\u0442\u0430\u0435\u0442 config\/componenta-providers.php, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u043f\u0430\u043a\u0435\u0442\u043e\u0432, \u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u043a\u043e\u043d\u0444\u0438\u0433-\u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440\u044b \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a. AttributeConfigProvider \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442 \u043f\u043e \u043d\u0430\u0439\u0434\u0435\u043d\u043d\u044b\u043c \u043a\u043b\u0430\u0441\u0441\u0430\u043c, \u0438\u0449\u0435\u0442 #[AsConfig] \u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u043f\u0440\u0438\u043a\u043b\u0430\u0434\u043d\u044b\u0435 config provider-\u044b. FileProvider \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0444\u0430\u0439\u043b\u044b \u043f\u043e \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u0443. \u0418\u0437 \u044d\u0442\u0438\u0445 \u0431\u043b\u043e\u043a\u043e\u0432 \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u043e\u0431\u0449\u0438\u0439 \u043a\u043e\u043d\u0444\u0438\u0433 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.\u0414\u043b\u044f \u043f\u0440\u043e\u0434\u0430\u043a\u0448\u0435\u043d \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u043e\u0431\u0449\u0438\u0439 \u043a\u043e\u043d\u0444\u0438\u0433 \u043f\u0438\u0448\u0435\u0442\u0441\u044f \u0432 \u0444\u0430\u0439\u043b \u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u043d, \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440\u044b \u043d\u0435 \u0438\u043d\u0441\u0442\u0430\u043d\u0446\u0438\u0440\u0443\u044e\u0442\u0441\u044f, \u0434\u0438\u0441\u043a\u0430\u0432\u0435\u0440\u0438\u043d\u0433 \u043d\u0435 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442.\u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e \u043a\u0430\u043a \u043a\u043e\u043d\u0444\u0438\u0433 \u0441\u043e\u0431\u0440\u0430\u043d, \u043d\u0430 \u0435\u0433\u043e \u043e\u0441\u043d\u043e\u0432\u0435 \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.\u0414\u0430\u043b\u044c\u0448\u0435 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442\u0441\u044f \u0443\u0436\u0435 \u043d\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u0430\u044f, \u0430 \u0440\u0430\u043d\u0442\u0430\u0439\u043c \u0447\u0430\u0441\u0442\u044c. \u0422\u043e\u0447\u043a\u0430 \u0432\u0445\u043e\u0434\u0430 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 Componenta\\App\\run() \u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442 \u0442\u0443\u0434\u0430 \u0441\u043a\u043e\u0443\u043f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0414\u043b\u044f HTTP \u044d\u0442\u043e Scope::HTTP, \u0434\u043b\u044f \u043a\u043e\u043d\u0441\u043e\u043b\u0438 \u0431\u0443\u0434\u0435\u0442 CLI, \u0434\u043b\u044f websocket \u0441\u0435\u0440\u0432\u0435\u0440\u0430 Scope::Websocket.\u0423\u043f\u0440\u043e\u0449\u0435\u043d\u043d\u043e run() \u0434\u0435\u043b\u0430\u0435\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u0435\u0449\u0435\u0439:&lt;?phpfunction run(ScopeInterface $scope, PathResolverInterface $paths): void{    chdir($paths-&gt;baseDir);    $container = require $paths-&gt;resolve(&#8216;config\/container.php&#8217;);    $config = $container-&gt;get(Config::class);    $code = Runner::run($scope, new ContainerValue($container, $config));    if ($code !== null) {        exit($code);    }}ContainerValue \u043f\u043e \u0441\u0443\u0442\u0438 \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0441\u0430\u0445\u0430\u0440 \u043d\u0430\u0434 PSR-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u043e\u043c. \u041e\u043d \u043d\u0435 \u0437\u0430\u043c\u0435\u043d\u044f\u0435\u0442 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0438 \u043d\u0435 \u0432\u0432\u043e\u0434\u0438\u0442 \u043d\u043e\u0432\u044b\u0439 DI-\u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c. \u042d\u0442\u043e \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0430\u044f \u043e\u0431\u0435\u0440\u0442\u043a\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0434\u0435\u0440\u0436\u0438\u0442 \u0440\u044f\u0434\u043e\u043c \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0438 \u0443\u0436\u0435 \u0441\u043e\u0431\u0440\u0430\u043d\u043d\u044b\u0439 Config.\u0421\u0435\u0439\u0447\u0430\u0441 \u043e\u043d \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0442\u0430\u043a:&lt;?phpdeclare(strict_types=1);namespace Componenta\\Config;use Componenta\\Config\\Exception\\InvalidContainerValueException;use Psr\\Container\\ContainerInterface;final readonly class ContainerValue implements ContainerInterface{    public Config $config;    public function __construct(        public ContainerInterface $value,        ?Config $config = null,    ) {        $this-&gt;config = $config ?? $this-&gt;resolveConfig();    }    public function has(string $id): bool    {        return $this-&gt;value-&gt;has($id);    }    \/**     * @template T of object     * @param class-string&lt;T&gt;|null $type     * @return ($type is null ? mixed : T)     *\/    public function get(string $id, ?string $type = null): mixed    {        $service = $this-&gt;value-&gt;get($id);        if ($type === null) {            return $service;        }        if (!$service instanceof $type) {            throw InvalidContainerValueException::forService($id, $type, $service);        }        return $service;    }    public function find(string $id, mixed $default = null): mixed    {        if ($this-&gt;value-&gt;has($id)) {            $type = $default instanceof ContainerEntry ? $default-&gt;type : null;            return $this-&gt;get($id, $type);        }        if ($default instanceof ContainerEntry) {            return $default-&gt;resolve($this);        }        if ($default instanceof ConfigEntry) {            return $default-&gt;resolve($this-&gt;config);        }        if ($default instanceof LazyValue) {            return $default-&gt;resolve($this);        }        return $default;    }    private function resolveConfig(): Config    {        if (!$this-&gt;value-&gt;has(Config::class)) {            return new Config([]);        }        return $this-&gt;get(Config::class, Config::class);    }}\u0417\u0430\u0447\u0435\u043c \u0437\u0434\u0435\u0441\u044c get(), \u0435\u0441\u043b\u0438 \u0443 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 \u0443\u0436\u0435 \u0435\u0441\u0442\u044c get()? \u0412 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c \u0440\u0430\u0434\u0438 \u0432\u0442\u043e\u0440\u043e\u0433\u043e \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430. \u041e\u0431\u044b\u0447\u043d\u044b\u0439 PSR-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 mixed, \u0430 ContainerValue::get(Foo::class, Foo::class) \u0441\u0440\u0430\u0437\u0443 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0442\u0438\u043f. \u0415\u0441\u043b\u0438 \u0432 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0435 \u043f\u043e\u0434 \u044d\u0442\u0438\u043c id \u0432\u043d\u0435\u0437\u0430\u043f\u043d\u043e \u043b\u0435\u0436\u0438\u0442 \u043d\u0435 Foo, \u043e\u0448\u0438\u0431\u043a\u0430 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043d\u044f\u0442\u043d\u043e\u0439 \u0438 \u0440\u0430\u043d\u043d\u0435\u0439.find() \u043d\u0443\u0436\u0435\u043d \u0434\u043b\u044f \u0434\u0440\u0443\u0433\u043e\u0433\u043e \u0441\u043b\u0443\u0447\u0430\u044f: \u0441\u0435\u0440\u0432\u0438\u0441 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u043c. \u0411\u0435\u0437 \u043d\u0435\u0433\u043e \u043a\u043e\u0434 \u0431\u044b\u0441\u0442\u0440\u043e \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u0432 \u043e\u0434\u043d\u043e\u0442\u0438\u043f\u043d\u044b\u0435 \u0432\u0435\u0442\u043a\u0438 has() \u043f\u043b\u044e\u0441 get() \u043f\u043b\u044e\u0441 fallback. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0435\u0441\u043b\u0438 \u0441\u0435\u0440\u0432\u0438\u0441 \u0435\u0441\u0442\u044c, \u0431\u0435\u0440\u0435\u043c \u0435\u0433\u043e. \u0415\u0441\u043b\u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u043d\u0435\u0442, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e. \u0410 \u0435\u0441\u043b\u0438 fallback \u0437\u0430\u0434\u0430\u043d \u043a\u0430\u043a ContainerEntry, ConfigEntry \u0438\u043b\u0438 LazyValue, \u043e\u043d \u0431\u0443\u0434\u0435\u0442 \u0430\u043a\u043a\u0443\u0440\u0430\u0442\u043d\u043e \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d \u0447\u0435\u0440\u0435\u0437 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0438\u043b\u0438 \u043a\u043e\u043d\u0444\u0438\u0433.\u0422\u043e \u0435\u0441\u0442\u044c \u0443\u0441\u043b\u043e\u0432\u043d\u043e \u0432\u043c\u0435\u0441\u0442\u043e \u0442\u0430\u043a\u043e\u0433\u043e:$foo = $container-&gt;has(FooInterface::class)    ? $container-&gt;get(FooInterface::class)    : $container-&gt;get(DefaultFoo::class); \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0430\u043a:  $foo = $container-&gt;find(    FooInterface::class,    new ContainerEntry(DefaultFoo::class, FooInterface::class),);\u042d\u0442\u043e \u043d\u0435 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0446\u0438\u044f, \u0441\u043a\u043e\u0440\u0435\u0435 \u0440\u0430\u0431\u043e\u0447\u0438\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0432\u043d\u0443\u0442\u0440\u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430, \u0433\u0434\u0435 \u0442\u0430\u043a\u0438\u0445 \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0445 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u043c\u043d\u043e\u0433\u043e: \u0444\u0430\u0431\u0440\u0438\u043a\u0438, bootloader-\u044b, \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0435 \u043f\u0430\u043a\u0435\u0442\u044b, \u0440\u0430\u0437\u043d\u044b\u0435 \u0441\u043a\u043e\u0443\u043f\u044b \u0437\u0430\u043f\u0443\u0441\u043a\u0430.\u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e Runner \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u0441\u0430\u043c\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043f\u043e\u0434 \u043d\u0443\u0436\u043d\u044b\u0439 \u0441\u043a\u043e\u0443\u043f. \u0412 HTTP  \u044d\u0442\u043e HTTP application, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0443\u043c\u0435\u0435\u0442 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c middleware \u0438 \u0432 \u043a\u043e\u043d\u0446\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c PSR-7 response \u0447\u0435\u0440\u0435\u0437 emitter. \u041f\u043e\u0442\u043e\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043e\u0431\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0432 boot target. \u0414\u043b\u044f HTTP \u044d\u0442\u043e HttpBootTargetInterface, \u0443 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0435\u0441\u0442\u044c \u043c\u0435\u0442\u043e\u0434 pipe().\u0417\u0430\u0442\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f BootContext:&lt;?phpfinal readonly class&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-484535","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/484535","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=484535"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/484535\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=484535"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=484535"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=484535"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}