{"id":345857,"date":"2023-02-25T09:00:29","date_gmt":"2023-02-25T09:00:29","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=345857"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=345857","title":{"rendered":"<span>Clean Architecture, DDD, \u0433\u0435\u043a\u0441\u0430\u0433\u043e\u043d\u0430\u043b\u044c\u043d\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430. \u0420\u0430\u0437\u0431\u0438\u0440\u0430\u0435\u043c \u043d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 blog \u043d\u0430 Symfony<\/span>"},"content":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0412\u0441\u0435\u043c \u043f\u0440\u0438\u0432\u0435\u0442! \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \ud83d\ude09 \u042f \u0410\u043d\u044f, \u0438 \u044f php \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a. \u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0441\u0442\u0435\u043a &#8212; Magento. \u0421 \u043d\u0435\u0434\u0430\u0432\u043d\u0438\u0445 \u043f\u043e\u0440 \u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u043e\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0442\u044c <s>\u043d\u0430\u043b\u0435\u0432\u043e<\/s> \u043d\u0430 Symfony \u0438 \u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u0438 Pet Projects \u043d\u0430 \u044d\u0442\u043e\u043c \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0435.  <\/p>\n<p>\u041c\u043d\u0435 \u0432\u0441\u0435\u0433\u0434\u0430 \u043d\u0440\u0430\u0432\u0438\u043b\u043e\u0441\u044c \u043f\u0438\u0441\u0430\u0442\u044c \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043b\u0435\u0433\u043a\u043e \u0431\u044b \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u043b\u0438\u0441\u044c \/ \u0430\u0434\u0430\u043f\u0442\u0438\u0440\u043e\u0432\u0430\u043b\u0438\u0441\u044c \u043f\u043e\u0434 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u0431\u0438\u0437\u043d\u0435\u0441\u0430 (\u0437\u0430\u043a\u0430\u0437\u0447\u0438\u043a\u0430). \u0418 \u043c\u043d\u0435 \u0432\u0441\u0435\u0433\u0434\u0430 \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u044d\u0442\u043e \u0431\u043e\u043b\u0435\u0435 &#8216;\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e&#8217; \u0438 \u043a\u0440\u0430\u0441\u0438\u0432\u043e. \u0422\u0430\u043a \u044f \u0438 \u043f\u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u043b\u0430\u0441\u044c \u0441 \u043f\u043e\u043d\u044f\u0442\u0438\u044f\u043c\u0438  \u0447\u0438\u0441\u0442\u043e\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043e\u0439.<\/p>\n<p>\u041c\u043e\u0439 \u043f\u043e\u0441\u0442 \u043d\u0438 \u0432 \u043a\u043e\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043d\u0435 \u043f\u0440\u0435\u0442\u0435\u043d\u0434\u0443\u0435\u0442 \u043d\u0430 \u0441\u0430\u043c\u044b\u0439 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0439. \u041d\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044c\u0442\u0435 \u043c\u043d\u0435 \u0437\u0434\u0435\u0441\u044c \u0434\u043e\u043d\u0435\u0441\u0442\u0438 \u0441\u0432\u043e\u0438 \u0438\u0434\u0435\u0438. \u0412 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u0445 \u0431\u0443\u0434\u0443 \u0440\u0430\u0434\u0430 \u0443\u0441\u043b\u044b\u0448\u0430\u0442\u044c \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u0438\u0432\u043d\u0443\u044e \u043a\u0440\u0438\u0442\u0438\u043a\u0443 \u043a \u0434\u0430\u043d\u043d\u043e\u043c\u0443 \u043f\u043e\u0441\u0442\u0443. <\/p>\n<p>\u0414\u043b\u044f \u043d\u0435\u0442\u0435\u0440\u043f\u0435\u043b\u0438\u0432\u044b\u0445, \u0432\u043e\u0442 <a href=\"https:\/\/github.com\/annysmolyan\/symfony-ddd-clean-architecture-blog\" rel=\"noopener noreferrer nofollow\">\u043f\u0440\u044f\u043c\u0430\u044f \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0433\u0438\u0442\u0445\u0430\u0431<\/a><\/p>\n<h2>\u0421\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435 \u0441\u0442\u0430\u0442\u044c\u0438 (\u0422\u0435\u043e\u0440\u0435\u0442\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u0447\u0430\u0441\u0442\u044c)<\/h2>\n<ol>\n<li>\n<p><a href=\"#ddd\" rel=\"noopener noreferrer nofollow\">\u0427\u0442\u043e \u0442\u0430\u043a\u043e\u0435 DDD<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#hexagonal\" rel=\"noopener noreferrer nofollow\">\u0427\u0442\u043e \u0442\u0430\u043a\u043e\u0435 \u0433\u0435\u043a\u0441\u0430\u0433\u043e\u043d\u0430\u043b\u044c\u043d\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#clean\" rel=\"noopener noreferrer nofollow\">\u0427\u0442\u043e \u0442\u0430\u043a\u043e\u0435 \u0447\u0438\u0441\u0442\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#advantages\" rel=\"noopener noreferrer nofollow\">\u041f\u043b\u044e\u0441\u044b \u0438 \u043c\u0438\u043d\u0443\u0441\u044b &#171;\u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043d\u043e\u0439&#187; \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438<\/a><\/p>\n<\/li>\n<\/ol>\n<h2>\u0421\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435 \u0441\u0442\u0430\u0442\u044c\u0438 (\u041f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u0447\u0430\u0441\u0442\u044c)<\/h2>\n<ol>\n<li>\n<p><a href=\"#development\" rel=\"noopener noreferrer nofollow\">\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#features\" rel=\"noopener noreferrer nofollow\">\u0420\u0430\u0437\u0431\u0438\u0432\u0430\u0435\u043c \u043f\u0440\u043e\u0435\u043a\u0442 \u043d\u0430 \u0444\u0438\u0447\u0438<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#data_work\" rel=\"noopener noreferrer nofollow\">\u0420\u0430\u0431\u043e\u0442\u0430 \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438: DataManagerFeatureApi<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#doctrineFeature\" rel=\"noopener noreferrer nofollow\">\u041c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0446\u0438\u044f \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438: DoctrineDataFeature (implements DataManagerFeatureApi)<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#category_feature\" rel=\"noopener noreferrer nofollow\">CategoryFeatureApi \u0438 CategoryFeature<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#post_feature\" rel=\"noopener noreferrer nofollow\">PostFeatureApi \u0438 PostFeature<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#front\" rel=\"noopener noreferrer nofollow\">FrontFeature<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/the_end\" rel=\"noopener noreferrer nofollow\">\u0418\u0442\u043e\u0433\u043e\u0432\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442<\/a><\/p>\n<\/li>\n<\/ol>\n<p>\u041f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u043c\u044b \u043d\u0430\u0447\u043d\u0451\u043c \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0442\u044c \u043a\u0430\u043a \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0431\u043b\u043e\u0433 \u043d\u0430 Symfony \u0441 DDD \u0438 Clean Architecture, \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u043c \u043e\u0441\u043d\u043e\u0432\u043d\u0443\u044e \u0442\u0435\u043e\u0440\u0438\u044e. \u0418 \u0442\u0430\u043a, \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c\u2026<\/p>\n<h2>\u0427\u0442\u043e \u0442\u0430\u043a\u043e\u0435 DDD (Domain Driven Design | Domain Driven Development)<\/h2>\n<p><a class=\"anchor\" name=\"ddd\" id=\"ddd\"><\/a><\/p>\n<p><strong>DDD (Domain Driven Design | Domain Driven Development)<\/strong> \u2013 \u044d\u0442\u043e <u>\u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043d\u044b\u0439<\/u> <u>\u043f\u043e\u0434\u0445\u043e\u0434<\/u>,  \u0437\u0430\u0434\u0430\u0447\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u2013 \u044d\u0442\u043e \u0432\u044b\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0431\u0438\u0437\u043d\u0435\u0441 \u043b\u043e\u0433\u0438\u043a\u0438 (Domain) \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u041e\u0442\u0441\u044e\u0434\u0430 \u0438 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u2013 Domain Driven. \u0417\u0434\u0435\u0441\u044c \u0442\u0430\u043a\u0436\u0435 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u044e\u0442\u0441\u044f \u0432\u043e \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043a\u043b\u0430\u0441\u0441\u043e\u0432, \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u044b, \u0445\u043e\u0440\u043e\u0448\u0438\u0435 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0438 \u0438 \u0442\u0434, \u043d\u043e \u044d\u0442\u043e \u0432\u0441\u0435 \u0432\u043d\u0443\u0442\u0440\u0438 \u0434\u043e\u043c\u0435\u043d\u043d\u043e\u0433\u043e \u0441\u043b\u043e\u044f. <\/p>\n<p>\u0414\u043e\u043c\u0435\u043d\u043d\u044b\u0439 \u0441\u043b\u043e\u0439 (Domain) \u043d\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c \u043e\u0442 \u0432\u043d\u0435\u0448\u043d\u0438\u0445 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a, Domain \u043d\u0435 \u043f\u0440\u0438\u0432\u044f\u0437\u0430\u043d \u043a \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445, \u043a \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u043e\u043c\u0443 \u0434\u0432\u0438\u0436\u043a\u0443 \u0438 \u043d\u0438\u043a\u043e\u0433\u0434\u0430 \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0437\u043d\u0430\u0435\u0442 \u043f\u0440\u043e \u0434\u0435\u0442\u0430\u043b\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0432\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043a\u0430\u043a\u0443\u044e \u0411\u0414 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c, \u0432\u0438\u0434 \u043a\u0435\u0448\u0430 \u0438 \u0442\u0434). \u0422\u0430\u043a\u0436\u0435 \u0434\u043e\u043c\u0435\u043d\u043d\u044b\u0439 \u0441\u043b\u043e\u0439 \u043d\u0435 \u043f\u0440\u0438\u0432\u044f\u0437\u0430\u043d \u043a \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0443, \u0435\u0441\u043b\u0438 \u0432\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0435, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, DDD \u043d\u0430 Symfony, \u0442\u043e \u0432 \u0438\u0434\u0435\u0430\u043b\u0435, \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0435\u043d\u043d\u044b\u0439 \u0434\u043e\u043c\u0435\u043d\u043d\u044b\u0439 \u0441\u043b\u043e\u0439 \u043d\u0430 Laravel (\u043b\u0438\u0431\u043e \u0434\u0440\u0443\u0433\u043e\u0439 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a), \u0434\u043e\u043b\u0436\u0435\u043d \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u0441\u0432\u043e\u044e \u0440\u0430\u0431\u043e\u0442\u043e\u0441\u043f\u043e\u0441\u043e\u0431\u043d\u043e\u0441\u0442\u044c.<\/p>\n<p>\u0418\u043d\u044b\u043c\u0438 \u0441\u043b\u043e\u0432\u0430\u043c\u0438, Domain \u2013 \u044d\u0442\u043e \u0441\u0435\u0440\u0434\u0446\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u0437\u0430\u0449\u0438\u0449\u0435\u043d\u043d\u043e\u0435 \u043e\u0442 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0438\u0437\u0432\u043d\u0435. \u0417\u0434\u0435\u0441\u044c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u044f\u0442 \u0441\u0430\u043c\u044b\u0435 \u0432\u0430\u0436\u043d\u044b\u0435 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u044b, \u043a\u0430\u0441\u0430\u0435\u043c\u044b\u0435 \u0431\u0438\u0437\u043d\u0435\u0441-\u043f\u0440\u0430\u0432\u0438\u043b, \u0442\u043e, \u0431\u0435\u0437 \u0447\u0435\u0433\u043e \u0431\u0438\u0437\u043d\u0435\u0441 \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c.<\/p>\n<p><strong>\u0421\u043e\u0432\u0441\u0435\u043c \u043a\u0440\u0430\u0442\u043a\u043e<\/strong>: <strong>Domain Driven Design | Domain Driven Development \u2013 <\/strong>\u044d\u0442\u043e \u0432\u044b\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0431\u0438\u0437\u043d\u0435\u0441 \u043b\u043e\u0433\u0438\u043a\u0438 \u0438 \u0435\u0433\u043e \u0438\u0437\u043e\u043b\u044f\u0446\u0438\u044f \u043e\u0442 \u0432\u043d\u0435\u0448\u043d\u0438\u0445 \u0444\u0430\u043a\u0442\u043e\u0440\u043e\u0432.<\/p>\n<h2>\u0427\u0442\u043e \u0442\u0430\u043a\u043e\u0435 \u0433\u0435\u043a\u0441\u0430\u0433\u043e\u043d\u0430\u043b\u044c\u043d\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 (Hexagonal architecture)<\/h2>\n<p><a class=\"anchor\" name=\"hexagonal\" id=\"hexagonal\"><\/a><\/p>\n<p><strong>\u0413\u0435\u043a\u0441\u0430\u0433\u043e\u043d\u0430\u043b\u044c\u043d\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430<\/strong> \u2013 \u044d\u0442\u043e <u>\u0432\u0438\u0434<\/u> <u>\u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b<\/u>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u0441\u043f\u043e\u0441\u043e\u0431 \u043e\u0431\u0449\u0435\u043d\u0438\u044f \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0434\u0440\u0443\u0433 \u0441 \u0434\u0440\u0443\u0433\u043e\u043c \u043f\u0443\u0442\u0435\u043c \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 \u0441\u043b\u043e\u0438 (layers), \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432 \u0441\u0432\u043e\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 \u0442\u0430\u043a \u043d\u0430\u0437\u044b\u0432\u0430\u0435\u043c\u044b\u0435 \u043f\u043e\u0440\u0442\u044b \u0434\u043b\u044f \u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0434\u0440\u0443\u0433 \u0441 \u0434\u0440\u0443\u0433\u043e\u043c.  <\/p>\n<p>\u0427\u0442\u043e \u0442\u0430\u043a\u043e\u0435 \u043f\u043e\u0440\u0442 \u0432 \u0433\u0435\u043a\u0441\u0430\u0433\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0435? \u0415\u0441\u043b\u0438 \u0433\u043e\u0432\u043e\u0440\u0438\u0442\u044c \u044f\u0437\u044b\u043a\u043e\u043c \u041e\u041e\u041f \u2013 \u044d\u0442\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441. \u041a\u0430\u0436\u0434\u044b\u0439 \u0441\u043b\u043e\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u043f\u043e\u0440\u0442-\u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0434\u0440\u0443\u0433\u043e\u0433\u043e \u0441\u043b\u043e\u044f, \u0430 \u043d\u0435 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u0443\u044e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e. <\/p>\n<p><strong>\u0427\u0442\u043e \u0436\u0435 \u0442\u0430\u043a\u043e\u0435 \u0441\u043b\u043e\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 (application\u2019s layers)? <\/strong> <\/p>\n<p>\u0418 \u0442\u0430\u043a, \u0441\u043b\u043e\u0439 \u2013 \u044d\u0442\u043e \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u043a\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u0433\u0434\u0435 \u043a\u0430\u0436\u0434\u0430\u044f \u0433\u0440\u0443\u043f\u043f\u0430 \u0438\u043c\u0435\u0435\u0442 \u0441\u0432\u043e\u0435 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0435 \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435. \u0412 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u043d\u0443\u0436\u0434 \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u043c\u043e\u0433\u0443\u0442 \u043f\u043e\u044f\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0441\u043b\u043e\u0438, \u043b\u0438\u0431\u043e \u0441\u043e\u043a\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0441\u043b\u043e\u0435\u0432.<\/p>\n<p>\u0421\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u0430\u0440\u0438\u0430\u0446\u0438\u0439, \u043d\u043e \u043d\u0430 \u043c\u043e\u0439 \u0432\u0437\u0433\u043b\u044f\u0434, \u0441\u0430\u043c\u044b\u043c \u043e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u043c \u0440\u0435\u0448\u0435\u043d\u0438\u0435\u043c \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0440\u0430\u0437\u0431\u0438\u0435\u043d\u0438\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0441\u043b\u043e\u0438:<\/p>\n<p><strong><u>Presentation Layer (\u0441\u043b\u043e\u0439 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f)<\/u> <\/strong>\u2013 \u0437\u0434\u0435\u0441\u044c \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432\u0441\u0435, \u0447\u0442\u043e \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 input\/output (\u0432\u0432\u043e\u0434\/\u0432\u044b\u0432\u043e\u0434), \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0448\u0430\u0431\u043b\u043e\u043d\u044b, \u043a\u043e\u043d\u0441\u043e\u043b\u044c\u043d\u044b\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u044b, \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u044b. \u0412\u0435\u0441\u044c input\/output \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0432 DTO Request (data transfer object) \u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442\u0441\u044f \u043d\u0430 \u0441\u043b\u043e\u0439 \u043d\u0438\u0436\u0435, \u0432 Application Layer. \u0422\u0430\u043a \u0436\u0435, \u0434\u0430\u043d\u043d\u044b\u0439 \u0441\u043b\u043e\u0439 \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442\u0441\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435\u043c DTO Response \u0438\u0437 Application Layer. \u0417\u0434\u0435\u0441\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0432\u0432\u043e\u0434 \u0438 \u0432\u044b\u0432\u043e\u0434, \u043d\u0438\u043a\u0430\u043a\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0439 \u0441\u043b\u043e\u0439 \u0432 \u0441\u0435\u0431\u0435 \u043d\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442.  <\/p>\n<p><strong><u>Application<\/u><\/strong><u> <\/u><strong><u>Layer (\u0441\u043b\u043e\u0439 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f)<\/u> <\/strong>\u2013 \u043f\u0440\u043e\u0441\u043b\u043e\u0439\u043a\u0430 \u043c\u0435\u0436\u0434\u0443 Domain \u0438 Presentation, \u0437\u0434\u0435\u0441\u044c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438e DTO Request \u0438\u0437 input\/output (Presentaion Layer), \u043f\u0435\u0440\u0432\u0438\u0447\u043d\u0430\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \/ \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044f \u0432\u0432\u043e\u0434\u0430, \u043c\u0430\u043f\u043f\u0438\u043d\u0433 DTO \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0432 Domain Layer \u0438 \u043d\u0430\u043e\u0431\u043e\u0440\u043e\u0442, \u0432\u044b\u0437\u043e\u0432 \u0431\u0438\u0437\u043d\u0435\u0441 \u043b\u043e\u0433\u0438\u043a\u0438 \u0438\u0437 Domain Layer.  <\/p>\n<p>\u0418\u043d\u044b\u043c\u0438 \u0441\u043b\u043e\u0432\u0430\u043c\u0438, \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u0440\u0435\u043a\u0432\u0435\u0441\u0442, \u043f\u0440\u043e\u0438\u0437\u0432\u0435\u043b\u0438 \u043c\u0430\u043f\u043f\u0438\u043d\u0433 \u0432 Domain Entity, \u0432\u044b\u0437\u0432\u0430\u043b\u0438 \u0438\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u043e\u0440 \/ usecase, \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043e\u0442 Domain Layer, \u0441\u0434\u0435\u043b\u0430\u043b\u0438 \u043c\u0430\u043f\u0438\u043d\u0433 \u0432 DTO Response \u0438 \u0432\u0435\u0440\u043d\u0443\u043b\u0438 \u043d\u0430 \u0441\u043b\u043e\u0439 Presentation, \u0433\u0434\u0435 \u0443\u0436\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043a\u0430\u0437\u0430\u043d \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e (\u0435\u0441\u043b\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e)<\/p>\n<p><strong><u>Domain<\/u><\/strong><u> <\/u><strong><u>Layer (\u0434\u043e\u043c\u0435\u043d\u043d\u044b\u0439 \u0441\u043b\u043e\u0439)<\/u> <\/strong>\u2013 \u0441\u043b\u043e\u0439 \u0441 \u0431\u0438\u0437\u043d\u0435\u0441 \u043b\u043e\u0433\u0438\u043a\u043e\u0439. \u0427\u0443\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u043c \u0432  \u0440\u0430\u0437\u0434\u0435\u043b\u0435 <strong>Clean<\/strong> <strong>Architecture. <\/strong>\u0412\u0410\u0416\u041d\u041e: \u0412 \u0438\u0434\u0435\u0430\u043b\u0435, \u0434\u043e\u043c\u0435\u043d\u043d\u044b\u0439 \u0441\u043b\u043e\u0439 \u043d\u0435 \u0437\u043d\u0430\u0435\u0442 \u043f\u0440\u043e \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u043d\u0438\u0435 \u0434\u0440\u0443\u0433\u0438\u0445 \u0441\u043b\u043e\u0435\u0432.<\/p>\n<p><strong><u>Infrastructure<\/u><\/strong> \u2013 \u0441\u043b\u043e\u0439, \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u0439 \u0441\u043e \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u043c\u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430\u043c\u0438, \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430\u043c\u0438 \u0438 \u0442\u0434.<\/p>\n<p>           \u041d\u0430\u0433\u043b\u044f\u0434\u043d\u043e \u0441\u0445\u0435\u043c\u0443 \u0441\u043b\u043e\u0435\u0432 \u0432 \u0433\u0435\u043a\u0441\u0430\u0433\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0435 \u043c\u043e\u0436\u043d\u043e \u0438\u0437\u043e\u0431\u0440\u0430\u0437\u0438\u0442\u044c \u0442\u0430\u043a:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/2a7\/0e5\/cd6\/2a70e5cd6f32c6734dd928af18fe696c.png\" width=\"1092\" height=\"617\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/2a7\/0e5\/cd6\/2a70e5cd6f32c6734dd928af18fe696c.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u0412\u0430\u0436\u043d\u043e \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e \u043a\u0430\u0436\u0434\u044b\u0439 \u0441\u043b\u043e\u0439 \u0438\u043c\u0435\u0435\u0442 \u0441\u0432\u043e\u0438 \u043c\u0430\u043f\u043f\u0435\u0440\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u044e\u0442 \u043e\u0431\u044a\u0435\u043a\u0442 \u0438\u0437 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0441\u043b\u043e\u044f \u0432 \u043e\u0431\u044a\u0435\u043a\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0441\u043b\u043e\u044f. \u0411\u043e\u043b\u0435\u0435 \u0434\u0435\u0442\u0430\u043b\u044c\u043d\u043e \u043c\u044b \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u043c \u044d\u0442\u043e \u043d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435.<\/p>\n<h2>\u0427\u0442\u043e \u0442\u0430\u043a\u043e\u0435 \u0447\u0438\u0441\u0442\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 (Clean  Architecture)<\/h2>\n<p><a class=\"anchor\" name=\"clean\" id=\"clean\"><\/a><\/p>\n<p><strong>Clean<\/strong>  <strong>Architecture \u2013 <\/strong>\u0431\u044b\u043b\u0430 \u043e\u043f\u0438\u0441\u0430\u043d\u0430 \u0420\u043e\u0431\u0435\u0440\u0442\u043e\u043c \u041c\u0430\u0440\u0442\u0438\u043d\u043e\u043c (\u00ab\u0414\u044f\u0434\u044e\u0448\u043a\u043e\u0439 \u0411\u043e\u0431\u043e\u043c\u00bb) &#8212; \u043e\u0447\u0435\u043d\u044c \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e \u0435\u0433\u043e \u043a\u043d\u0438\u0433\u0438 \u043a \u043f\u0440\u043e\u0447\u0442\u0435\u043d\u0438\u044e. \u0414\u0430\u043d\u043d\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u043e\u0441\u043d\u043e\u0432\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043d\u0430 \u0433\u0435\u043a\u0441\u0430\u0433\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0435, \u043e\u0434\u043d\u0430\u043a\u043e \u0441 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u043c\u0438 \u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f\u043c\u0438. \u0417\u0434\u0435\u0441\u044c \u0432\u0432\u043e\u0434\u044f\u0442\u0441\u044f \u0442\u0430\u043a\u0438\u0435 \u043f\u043e\u043d\u044f\u0442\u0438\u044f, \u043a\u0430\u043a: Use Case, Interactor, Entity.<\/p>\n<p><strong>\u0427\u0442\u043e \u0436\u0435 \u0442\u0430\u043a\u043e\u0435 Domain Entity \u043f\u0440\u043e\u0441\u0442\u044b\u043c\u0438 \u0441\u043b\u043e\u0432\u0430\u043c\u0438?<\/strong> \u042d\u0442\u043e \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438, \u0431\u0435\u0437 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0431\u0438\u0437\u043d\u0435\u0441 \u043f\u0440\u043e\u0441\u0442\u043e \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u043c \u0431\u0430\u043d\u043a, \u0438 \u043e\u0442\u0431\u0440\u043e\u0441\u0438\u043c \u0432\u0441\u0435 \u0434\u0435\u0442\u0430\u043b\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438. \u0427\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u044f\u0432\u043b\u044f\u0442\u044c\u0441\u044f domain entity \u0434\u043b\u044f \u0431\u0430\u043d\u043a\u0430? \u042d\u0442\u043e \u043d\u0430\u0432\u0435\u0440\u043d\u044f\u043a\u0430 \u0431\u0443\u0434\u0435\u0442 UserEntity, AccountEntity \u0438 \u0442\u0434.<\/p>\n<p><strong>\u0427\u0442\u043e \u0436\u0435 \u0442\u0430\u043a\u043e\u0435 Use Case \u043f\u0440\u043e\u0441\u0442\u044b\u043c\u0438 \u0441\u043b\u043e\u0432\u0430\u043c\u0438?<\/strong> \u041f\u043e \u0441\u0443\u0442\u0438, \u044d\u0442\u043e \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u044b, \u0431\u0435\u0437 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0431\u0438\u0437\u043d\u0435\u0441. \u041d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0431\u0430\u043d\u043a\u0430, Use Case \u0431\u0443\u0434\u0435\u0442 \u044f\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u043e\u0442\u043a\u0440\u044b\u0442\u0438\u0435 \u0441\u0447\u0435\u0442\u0430, \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0432\u043a\u043b\u0430\u0434\u0430, \u0437\u0430\u043a\u0440\u044b\u0442\u0438\u0435 \u0441\u0447\u0435\u0442\u0430, \u0437\u0430\u043a\u0430\u0437 \u043a\u0430\u0440\u0442\u044b \u0438 \u0442\u0434.<\/p>\n<p><strong>\u0427\u0442\u043e \u0436\u0435 \u0442\u043e\u0433\u0434\u0430 Intercator \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442?<\/strong> \u042d\u0442\u043e \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c, \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u044e\u0449\u0438\u0439 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e Use Case. \u0413\u043e\u0432\u043e\u0440\u044f \u043d\u0430 \u044f\u0437\u044b\u043a\u0435 \u041e\u041e\u041f \u2013 \u044d\u0442\u043e \u043a\u043b\u0430\u0441\u0441, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043e\u043f\u0438\u0441\u0430\u043d\u044b \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e Use Case. \u041a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u044d\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043a\u043e\u0434 \u0431\u043e\u043b\u0435\u0435 \u043a\u043e\u043c\u043f\u0430\u043a\u0442\u043d\u044b\u043c.<\/p>\n<p>\u042f \u0441\u0442\u0430\u0440\u0430\u044e\u0441\u044c \u043f\u0440\u0438\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c\u0441\u044f \u0447\u0438\u0441\u0442\u043e\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b, \u043e\u043d\u0430 \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0432 \u0441\u0435\u0431\u044f \u0432\u0441\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0435, \u0447\u0442\u043e \u043d\u0443\u0436\u043d\u043e \u0434\u043b\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0441 \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u0443\u0435\u043c\u044b\u043c \u043a\u043e\u0434\u043e\u043c.<\/p>\n<p><strong>\u041f\u043b\u044e\u0441\u044b \u0438 \u043c\u0438\u043d\u0443\u0441\u044b \u0447\u0438\u0441\u0442\u043e\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b :<\/strong><\/p>\n<p><a class=\"anchor\" name=\"advantages\" id=\"advantages\"><\/a><\/p>\n<p>\u0423 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0430 \u0435\u0441\u0442\u044c \u043f\u043e\u043b\u043e\u0436\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0438 \u043e\u0442\u0440\u0438\u0446\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0441\u0442\u043e\u0440\u043e\u043d\u044b. \u041c\u043e\u0436\u043d\u043e \u0431\u0435\u0441\u043a\u043e\u043d\u0435\u0447\u043d\u043e \u0434\u043e\u043b\u0433\u043e \u0440\u0430\u0441\u0441\u0443\u0436\u0434\u0430\u0442\u044c \u043d\u0430 \u0442\u0435\u043c\u0443 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043d\u044b\u0445 \u043f\u043e\u0434\u0445\u043e\u0434\u043e\u0432, \u0438 \u0432\u044b\u0434\u0435\u043b\u0438\u0442\u044c \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u201c\u0437\u0430\u201d \u0438 \u201c\u043f\u0440\u043e\u0442\u0438\u0432\u201d, \u043e\u0434\u043d\u0430\u043a\u043e \u0437\u0434\u0435\u0441\u044c \u044f \u043f\u0440\u0438\u0432\u0435\u0434\u0443 \u0441\u0430\u043c\u044b\u0435 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043f\u0443\u043d\u043a\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435, \u043d\u0430 \u043c\u043e\u0439 \u0432\u0437\u0433\u043b\u044f\u0434, \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0441\u0430\u043c\u044b\u043c\u0438 \u0432\u0430\u0436\u043d\u044b\u043c\u0438.<\/p>\n<p><strong>\u041d\u0430\u0447\u043d\u0435\u043c \u0441 \u043c\u0438\u043d\u0443\u0441\u043e\u0432:<\/strong><\/p>\n<p><strong>&#8212; \u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0441 \u043a\u0430\u0434\u0440\u0430\u043c\u0438 <\/strong>\u2013 \u0434\u0430\u043b\u0435\u043a\u043e \u043d\u0435 \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0437\u043d\u0430\u0435\u0442 \u043f\u0440\u043e \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 \u0441\u043b\u043e\u0438, \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0443, \u0434\u0430 \u0438 \u0432 \u0446\u0435\u043b\u043e\u043c, \u0434\u043b\u044f \u0447\u0435\u0433\u043e \u044d\u0442\u043e \u043d\u0443\u0436\u043d\u043e. \u041e\u0442\u0441\u044e\u0434\u0430 \u0432\u044b\u0442\u0435\u043a\u0430\u0435\u0442 \u043f\u0443\u043d\u043a\u0442 \u043d\u0438\u0436\u0435<\/p>\n<p>&#8212;<strong> \u0414\u043e\u0440\u043e\u0433\u043e\u0432\u0438\u0437\u043d\u0430 \u0432 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 &#8212;<\/strong> \u0434\u0430\u043d\u043d\u044b\u0439 \u043f\u0443\u043d\u043a\u0442 \u043c\u043e\u0436\u043d\u043e \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u044c \u043d\u0430 2 \u043c\u043e\u043c\u0435\u043d\u0442\u0430. \u0412\u043e-\u043f\u0435\u0440\u0432\u044b\u0445, \u0442\u0430\u043a\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043a\u0430\u043a \u043c\u0438\u043d\u0438\u043c\u0443\u043c \u0433\u0440\u0430\u043c\u043e\u0442\u043d\u043e\u0433\u043e \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u043e\u0440\u0430, \u043b\u0438\u0431\u043e \u0441\u0435\u043d\u044c\u0435\u0440\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u0438\u043c\u0435\u0435\u0442 \u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0440\u0435\u0439\u0442 \u0437\u0430 \u0447\u0430\u0441. \u0412\u043e-\u0432\u0442\u043e\u0440\u044b\u0445, \u043d\u0430 \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u0435 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0437\u0430\u0434\u0430\u0447 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0431\u043e\u043b\u044c\u0448\u0435 \u0432\u0440\u0435\u043c\u0435\u043d\u0438, \u0442\u043a \u0432\u044b\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0434\u043e\u043c\u0435\u043d\u043d\u043e\u0433\u043e \u0441\u043b\u043e\u044f \u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u044d\u043a\u043e\u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0434\u043b\u044f \u043a\u043e\u043c\u043c\u0443\u043d\u0438\u043a\u0430\u0446\u0438\u0438 \u0441 \u0434\u043e\u043c\u0435\u043d\u043e\u043c \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0431\u041e\u043b\u044c\u0448\u0435\u0433\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u043a\u043e\u0434\u0430 (\u043d\u0430 \u043f\u0435\u0440\u0432\u044b\u0445 \u044d\u0442\u0430\u043f\u0430\u0445).<\/p>\n<p><strong>&#8212; \u041c\u043d\u043e\u0433\u043e \u043e\u0434\u043d\u043e\u0442\u0438\u043f\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430 (\u043d\u0435 \u043f\u0443\u0442\u0430\u0442\u044c \u0441 \u043a\u043e\u043f\u0438\u043f\u0430\u0441\u0442\u043e\u0439!)<\/strong> &#8212; \u043f\u0440\u0438\u0433\u043e\u0442\u043e\u0432\u044c\u0442\u0435\u0441\u044c \u043f\u0438\u0441\u0430\u0442\u044c \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u043a\u043e\u0434\u0430, \u0434\u0430 \u0438 \u0435\u0449\u0435 \u0441\u0445\u043e\u0436\u0435\u0433\u043e \u0434\u0440\u0443\u0433 \u0441 \u0434\u0440\u0443\u0433\u043e\u043c \u043e\u0442 \u0444\u0438\u0447\u0438 \u043a \u0444\u0438\u0447\u0435 (\u0438 \u043e\u0442 \u0441\u043b\u043e\u044f \u043a \u0441\u043b\u043e\u044e). \u0414\u0430, api, \u0432\u0435\u0447\u043d\u044b\u0435 \u043c\u0430\u043f\u043f\u0438\u043d\u0433\u0438 \u0438 \u0442\u0434 \u0438\u043d\u043e\u0433\u0434\u0430 \u043e\u0447\u0435\u043d\u044c \u0441\u0438\u043b\u044c\u043d\u043e \u043d\u0435\u0440\u0432\u0438\u0440\u0443\u044e\u0442.<\/p>\n<p><strong>&#8212; \u041f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u044b\u0439 \u0441\u0430\u043c\u043e\u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044c \u2013 <\/strong>\u0435\u0441\u043b\u0438 \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 \u044f\u0437\u044b\u043a\u0430 \u043d\u0435 \u043f\u0440\u0435\u0434\u0443\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043a\u043e\u0434\u0430 \u043d\u0430 \u043f\u0430\u043a\u0435\u0442\u044b (\u043a\u0430\u043a \u0432 Java), \u043d\u0443\u0436\u043d\u043e \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e \u0441\u0435\u0431\u044f \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043a\u043b\u0430\u0441\u0441\u044b\/\u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u044b \u0438\u0437 \u0434\u0440\u0443\u0433\u0438\u0445 \u0441\u043b\u043e\u0435\u0432\/\u0444\u0438\u0447, \u043c\u0438\u043d\u0443\u044f api.  <\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u043e\u0433\u043e\u0432\u043e\u0440\u0438\u043c \u043e <strong>\u043f\u043b\u044e\u0441\u0430\u0445 \u0447\u0438\u0441\u0442\u043e\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b<\/strong>:<\/p>\n<p><strong>&#8212; \u0421\u043b\u0430\u0431\u0430\u044f \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c \u043a\u043e\u0434\u0430 \u2013 <\/strong>\u0442\u043a \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u043e \u043d\u0430 \u0441\u043b\u043e\u0438, \u0433\u0434\u0435 \u043a\u0430\u0436\u0434\u044b\u0439 \u0441\u043b\u043e\u0439 \u0438\u0437\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u043d \u0434\u0440\u0443\u0433 \u043e\u0442 \u0434\u0440\u0443\u0433\u0430, \u0442\u043e \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0432 \u043e\u0434\u043d\u043e\u043c \u0441\u043b\u043e\u0435 \u043d\u0435 \u0432\u043b\u0438\u044f\u0435\u0442 \u043d\u0430 \u0434\u0440\u0443\u0433\u043e\u0439.<\/p>\n<p><strong>&#8212; \u041b\u0435\u0433\u043a\u043e \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u2013 <\/strong>\u0442\u043a \u0441\u043b\u043e\u0438 \u043d\u0435 \u0437\u0430\u0432\u0438\u0441\u044f\u0442 \u0434\u0440\u0443\u0433 \u043e\u0442 \u0434\u0440\u0443\u0433\u0430, \u0442\u043e \u043f\u0440\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u0431\u0438\u0437\u043d\u0435\u0441 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0432, \u043f\u0440\u043e\u0435\u043a\u0442 \u043c\u043e\u0436\u043d\u043e \u043b\u0435\u0433\u043a\u043e \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u043b\u0438\u0431\u043e \u0436\u0435 \u043d\u0430\u043e\u0431\u043e\u0440\u043e\u0442 \u2013 \u0443\u0431\u0440\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435 \u043d\u0443\u0436\u0435\u043d.<\/p>\n<p><strong>&#8212; \u041b\u0435\u0433\u043a\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u2013 <\/strong>\u0434\u0430\u043d\u043d\u044b\u0439 \u043a\u043e\u0434 \u0445\u043e\u0440\u043e\u0448\u043e \u043f\u043e\u0434\u0434\u0430\u0435\u0442\u0441\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e. \u0417\u0430 \u0441\u0447\u0435\u0442 \u0438\u0437\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u043a\u043e\u0434\u0430 \u043f\u043e \u0441\u043b\u043e\u044f\u043c, \u043f\u0440\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u043a\u043e\u0434\u0430 \u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0442\u0435\u0441\u0442\u043e\u0432.<\/p>\n<p><strong>&#8212; \u0414\u0435\u0448\u0435\u0432\u043e \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c<\/strong> \u2013 \u0434\u0430, \u0440\u0430\u0437\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u0434\u0443\u043a\u0442 \u0441 \u0442\u0430\u043a\u0438\u043c \u043f\u043e\u0434\u0445\u043e\u0434\u043e\u043c \u0434\u043e\u0440\u043e\u0433\u043e, \u043e\u0434\u043d\u0430\u043a\u043e, \u0435\u0441\u043b\u0438 \u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043d\u0430\u043f\u0435\u0440\u0441\u043f\u0435\u043a\u0442\u0438\u0432\u0443, \u0442\u043e \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0431\u0443\u0434\u0435\u0442 \u0434\u0435\u0448\u0435\u0432\u043b\u0435. \u0427\u0435\u0433\u043e \u043d\u0435\u043b\u044c\u0437\u044f \u0441\u043a\u0430\u0437\u0430\u0442\u044c \u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435 \u043f\u0440\u0438\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043d\u044b\u0445 \u043f\u043e\u0434\u0445\u043e\u0434\u043e\u0432.  <\/p>\n<p><strong>\u041a\u043e\u0433\u0434\u0430 \u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0447\u0438\u0441\u0442\u0443\u044e \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0443?<\/strong><\/p>\n<p>\u0427\u0438\u0441\u0442\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u2013 \u044d\u0442\u043e \u043e\u0447\u0435\u043d\u044c \u043c\u043e\u0449\u043d\u044b\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0435\u043c\u043e\u0433\u043e \u0438 \u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u042d\u0442\u043e \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u0435\u043e\u0440\u0438\u044f \/ \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f, \u043d\u043e \u0442\u0430\u043a \u0436\u0435 \u0438 \u043e\u0431\u0440\u0430\u0437 \u043c\u044b\u0448\u043b\u0435\u043d\u0438\u044f. \u041a\u043e\u0433\u0434\u0430 \u0436\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0447\u0438\u0441\u0442\u043e\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u043e\u043f\u0440\u0430\u0432\u0434\u044b\u0432\u0430\u0442\u044c \u0441\u0435\u0431\u044f? \u042f \u0431\u044b \u0441\u043a\u0430\u0437\u0430\u043b\u0430, \u0447\u0442\u043e \u043e\u043d\u0430 \u0432\u0441\u0435\u0433\u0434\u0430 \u0441\u0435\u0431\u044f \u043e\u043f\u0440\u0430\u0432\u0434\u044b\u0432\u0430\u0435\u0442. \u0412\u0435\u0434\u044c \u0445\u043e\u0440\u043e\u0448\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0435\u0449\u0435 \u043d\u0438\u043a\u043e\u0433\u0434\u0430 \u043d\u0435 \u0432\u044b\u0437\u044b\u0432\u0430\u043b\u043e \u043d\u0435\u0433\u0430\u0442\u0438\u0432\u043d\u043e\u0439  \u0440\u0435\u0430\u043a\u0446\u0438\u0438! \u041e\u0434\u043d\u0430\u043a\u043e \u043d\u0435 \u0441\u0442\u043e\u0438\u0442 \u0437\u0430\u0431\u044b\u0432\u0430\u0442\u044c \u043f\u0440\u043e \u043a\u043e\u043c\u043c\u0435\u0440\u0446\u0438\u044e \u0438 \u0431\u0438\u0437\u043d\u0435\u0441. \u041d\u0435 \u0432\u0441\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u044b, \u0443 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u044b \u0441 \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u043c \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u044b\u043c \u0446\u0438\u043a\u043b\u043e\u043c, \u0433\u043e\u0442\u043e\u0432\u044b \u043f\u043b\u0430\u0442\u0438\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u0435 \u0437\u0430 \u0445\u043e\u0440\u043e\u0448\u0443\u044e \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0443. \u041d\u043e \u044d\u0442\u043e \u043d\u0435 \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043e \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u044b \u043d\u0435 \u0437\u0430\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u044e\u0442 \u0445\u043e\u0440\u043e\u0448\u0435\u0433\u043e \u043a\u043e\u0434\u0430! =)<\/p>\n<p>\u0418 \u0442\u0430\u043a, \u0442\u0435\u043f\u0435\u0440\u044c \u043a \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435:<\/p>\n<h2>\u041f\u0440\u0430\u043a\u0442\u0438\u043a\u0430: \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0431\u043b\u043e\u0433\u0430 \u043d\u0430 Symfony \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0447\u0438\u0441\u0442\u043e\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b (Clean Architecture)<\/h2>\n<p><a class=\"anchor\" name=\"development\" id=\"development\"><\/a><\/p>\n<p>\u0412\u044b\u0448\u0435 \u044f \u043f\u0438\u0441\u0430\u043b\u0430 \u043f\u0440\u043e \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 \u0441\u043b\u043e\u0438. \u041e\u0434\u043d\u0430\u043a\u043e \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0447\u0430\u0441\u0442\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0440\u0430\u0437\u0431\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430 \u0441\u043b\u043e\u0438, \u043d\u043e \u0438 \u043d\u0430 \u0444\u0438\u0447\u0438. \u041a\u0430\u0436\u0434\u0430\u044f \u0444\u0438\u0447\u0430 \u0438\u043c\u0435\u0435\u0442 \u0442\u0430\u043a\u043e\u0439 \u0436\u0435 \u043d\u0430\u0431\u043e\u0440 \u0441\u043b\u043e\u0435\u0432, \u0447\u0442\u043e \u0431\u044b\u043b\u0438 \u043e\u043f\u0438\u0441\u0430\u043d\u044b \u0432\u044b\u0448\u0435. (\u0434\u043e\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435\/\u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0445 \u0441\u043b\u043e\u0435\u0432 \u0432 \u0444\u0438\u0447\u0430\u0445). \u041c\u043d\u0435 \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0440\u0430\u0432\u0438\u0442\u0441\u044f \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043f\u043e \u0444\u0438\u0447\u0430\u043c.<\/p>\n<p>\u0418 \u0442\u0430\u043a, \u043a\u0430\u043a\u043e\u0439 \u043f\u043b\u0430\u043d? \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0431\u043b\u043e\u0433, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u043f\u043e\u0441\u0442\u043e\u0432 \u0438 \u0432\u044b\u0432\u043e\u0434 \u0438\u0445 \u0432 \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0438.<\/p>\n<p>\u041f\u0440\u0435\u0436\u0434\u0435, \u0447\u0435\u043c \u043d\u0430\u0447\u043d\u0435\u043c, \u0441\u043a\u0430\u0436\u0443 \u0441\u0440\u0430\u0437\u0443 \u2013 \u044f \u043d\u0435 \u0441\u0438\u043c\u0444\u043e\u043d\u0438 \u0434\u0435\u0432\u0435\u043b\u043e\u043f\u0435\u0440, \u043c\u043d\u0435 \u043d\u0440\u0430\u0432\u0438\u0442\u0441\u044f \u044d\u0442\u043e\u0442 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0438 \u043e\u0431\u043a\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u0441\u0432\u043e\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u044b\/\u0438\u0434\u0435\u0438. \u042f \u0437\u043d\u0430\u044e, \u0447\u0442\u043e \u0443 \u0441\u0438\u043c\u0444\u043e\u043d\u0438 \u0435\u0441\u0442\u044c \u0441\u0432\u043e\u0439 best practice , \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043e\u043f\u0438\u0441\u0430\u043d\u044b \u201c\u043f\u0430\u043f\u043e\u0447\u043a\u0438\u201d \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0438 \u0447\u0442\u043e \u0442\u0430\u043c \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c. \u041d\u043e \u043f\u0430\u043f\u043e\u0447\u043a\u0438 \u2013 \u044d\u0442\u043e \u043d\u0435 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430, \u043d\u0435 \u0442\u0430\u043a \u043b\u0438? \u0410 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u0442 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043b\u0435\u0433\u043a\u0443\u044e \u043a\u0430\u0441\u0442\u043e\u043c\u0438\u0437\u0430\u0446\u0438\u044e \u201c\u043f\u0430\u043f\u043e\u0447\u0435\u043a\u201d \u043f\u043e\u0434 \u0441\u0432\u043e\u0438 \u043d\u0443\u0436\u0434\u044b. \u0418 \u0432\u043e\u043e\u0431\u0449\u0435, \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u2013 \u044d\u0442\u043e \u0432\u0441\u0435\u0433\u043e \u043b\u0438\u0448\u044c \u0434\u0435\u0442\u0430\u043b\u044c \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438.<\/p>\n<p>\u0415\u0441\u043b\u0438 \u043a\u043e\u043c\u0443-\u0442\u043e \u043f\u0440\u043e\u0449\u0435 \u0441\u0440\u0430\u0437\u0443 \u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438, \u0442\u043e \u043e\u0441\u0442\u0430\u0432\u043b\u044e \u0435\u0449\u0435 \u0440\u0430\u0437 \u0442\u0443\u0442 \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 &#8212; <a href=\"https:\/\/github.com\/annysmolyan\/symfony-ddd-clean-architecture-blog\" rel=\"noopener noreferrer nofollow\">\u043f\u0440\u044f\u043c\u0430\u044f \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0433\u0438\u0442\u0445\u0430\u0431<\/a><\/p>\n<p>\u0418 \u0442\u0430\u043a, \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c.<\/p>\n<h3>\u0420\u0430\u0437\u0431\u0438\u0432\u0430\u0435\u043c \u043d\u0430 \u0444\u0438\u0447\u0438<\/h3>\n<p><a class=\"anchor\" name=\"features\" id=\"features\"><\/a><\/p>\n<p>\u041a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e \u043b\u044e\u0434\u0435\u0439, \u043f\u0440\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u041f\u041e, \u0432 \u043f\u0435\u0440\u0432\u0443\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u043e\u043f\u0438\u0440\u0430\u044e\u0442\u0441\u044f \u043d\u0430 \u0433\u0440\u0430\u0444\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0434\u0438\u0437\u0430\u0439\u043d, \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0441\u0442\u0440\u043e\u044f\u0442\u0441\u044f \u043c\u043e\u0434\u0435\u043b\u0438(\u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438) \u0438 \u043f\u0440\u043e\u0447\u0438\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u042d\u0442\u043e \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u0448\u0438\u0431\u043a\u043e\u0439. \u0422\u043a. \u0434\u0438\u0437\u0430\u0439\u043d \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0441\u044f \u043a \u0432\u0432\u043e\u0434\u0443\/\u0432\u044b\u0432\u043e\u0434\u0443 \u0438 \u043d\u0435 \u0434\u043e\u043b\u0436\u0435\u043d \u0438\u043c\u0435\u0442\u044c \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0432\u043b\u0438\u044f\u043d\u0438\u044f \u043d\u0430 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0443 \u043f\u0440\u043e\u0435\u043a\u0442\u0430. \u0412 \u043f\u0435\u0440\u0432\u0443\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c, \u044f \u0434\u0443\u043c\u0430\u044e \u043e \u0442\u043e\u043c, \u043d\u0430 \u043a\u0430\u043a\u0438\u0435 \u0447\u0430\u0441\u0442\u0438 (\u0444\u0438\u0447\u0438) \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d \u043f\u0440\u043e\u0435\u043a\u0442, \u0447\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u044f\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u0431\u0438\u0437\u043d\u0435\u0441 \u043b\u043e\u0433\u0438\u043a\u043e\u0439 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0439 \u0444\u0438\u0447\u0438, \u0438 \u043a\u0430\u043a \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u044d\u0442\u0438 \u0434\u0430\u043d\u043d\u044b\u0435.<\/p>\n<p>\u041a\u0430\u0436\u0434\u0430\u044f \u0444\u0438\u0447\u0430 \u0431\u0443\u0434\u0435\u0442 \u0438\u043c\u0435\u0442\u044c \u0441\u0432\u043e\u0439 \u043d\u0430\u0431\u043e\u0440 API \u0438 \u0435\u0433\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u0442\u044c (\u043d\u0435 \u043f\u0443\u0442\u0430\u0442\u044c \u0441 REST). \u042d\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u0431\u044b \u0438\u043c\u0435\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0442\u0430\u043a \u043d\u0430\u0437\u044b\u0432\u0430\u0435\u043c\u044b\u0435 \u201c\u043f\u043e\u0440\u0442\u044b\u201d \u0434\u043b\u044f \u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0444\u0438\u0447 \u0434\u0440\u0443\u0433 \u0441 \u0434\u0440\u0443\u0433\u043e\u043c \u0438 \u043d\u0435 \u0431\u044b\u0442\u044c \u043f\u0440\u0438\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u043c \u043a \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438. \u0422\u0435\u043f\u0435\u0440\u044c \u0444\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u0441\u043f\u0438\u0441\u043e\u043a \u0444\u0438\u0447:<\/p>\n<ul>\n<li>\n<p>CategoryFeature &#8212; \u0437\u0434\u0435\u0441\u044c \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430 \u0441 \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u044f\u043c\u0438<\/p>\n<\/li>\n<li>\n<p>CategoryFeatureAPI &#8212; \u043d\u0430\u0431\u043e\u0440 \u0430\u043f\u0438, \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u0439 \u0434\u043b\u044f \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0445 \u043c\u043e\u0434\u0443\u043b\u0435\u0439<\/p>\n<\/li>\n<li>\n<p>PostFeature &#8212; \u0437\u0434\u0435\u0441\u044c \u0440\u0430\u0431\u043e\u0442\u0430 \u0441 \u043f\u043e\u0441\u0442\u0430\u043c\u0438<\/p>\n<\/li>\n<li>\n<p>PostFeatureAPI &#8212; \u043d\u0430\u0431\u043e\u0440 \u0430\u043f\u0438, \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u0439 \u0434\u043b\u044f \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0445 \u043c\u043e\u0434\u0443\u043b\u0435\u0439<\/p>\n<\/li>\n<li>\n<p>DataManagerFeatureAPI &#8212; \u043d\u0430\u0431\u043e\u0440 \u0430\u043f\u0438, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0438\u0439 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 DataStorage (\u044d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0431\u0430\u0437\u0430 \u0434\u0430\u043d\u043d\u044b\u0445, \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0439 \u0444\u0430\u0439\u043b \u0438 \u0442\u0434)<\/p>\n<\/li>\n<li>\n<p>DoctrineDataFeature &#8212; \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u0435\u0442 DataManagerFeatureAPI \u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0441 \u0434\u043e\u043a\u0442\u0440\u0438\u043d\u043e\u0439<\/p>\n<\/li>\n<li>\n<p>FrontFeature &#8212; \u0440\u0430\u0431\u043e\u0442\u0430 \u0441 \u0444\u0440\u043e\u043d\u0442\u043e\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f (\u0448\u0430\u0431\u043b\u043e\u043d\u044b, \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u044b \u0438 \u0442\u0434). \u041d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0430\u043f\u0438.<\/p>\n<\/li>\n<li>\n<p>AdminFeature (\u043d\u0435 \u0431\u0443\u0434\u0443 \u0435\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u0442\u044c \u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435, \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u043c\u0430\u0448\u043d\u0438\u043c \u0437\u0430\u0434\u0430\u043d\u0438\u0435\u043c)<\/p>\n<\/li>\n<\/ul>\n<p><strong>                                                  \u041d\u0430\u0433\u043b\u044f\u0434\u043d\u0430\u044f \u0441\u0445\u0435\u043c\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430:<\/strong><\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/920\/875\/e0f\/920875e0f69903884a30cc32fc8cfc01.png\" width=\"958\" height=\"534\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/920\/875\/e0f\/920875e0f69903884a30cc32fc8cfc01.png\"\/><figcaption><\/figcaption><\/figure>\n<p>                                             <strong>\u041a\u0430\u043a \u044d\u0442\u043e \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0432 \u0441\u0430\u043c\u043e\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435:<\/strong><\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/bf3\/8a3\/8d5\/bf38a38d585da78e7f8a9353af4a58fe.png\" width=\"308\" height=\"288\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/bf3\/8a3\/8d5\/bf38a38d585da78e7f8a9353af4a58fe.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043d\u0430\u0447\u043d\u0435\u043c \u0441 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438\/\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445, \u0430 \u043f\u043e\u0442\u043e\u043c \u0432\u0435\u0440\u043d\u0435\u043c\u0441\u044f \u043a \u0444\u0438\u0447\u0430\u043c \u043f\u043e\u0441\u0442\u043e\u0432 \u0438 \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0439. \u041d\u0430 \u043c\u043e\u0439 \u0432\u0437\u0433\u043b\u044f\u0434, \u0442\u0430\u043a \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0449\u0435 \u043f\u043e\u043d\u044f\u0442\u044c.<\/p>\n<h2>\u0420\u0430\u0431\u043e\u0442\u0430 \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 (DataManagerFeatureApi)<\/h2>\n<p><a class=\"anchor\" name=\"data_work\" id=\"data_work\"><\/a><\/p>\n<p>\u042f \u043d\u0435 \u0445\u043e\u0447\u0443 \u043f\u0440\u0438\u0432\u044f\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043a \u0434\u043e\u043a\u0442\u0440\u0438\u043d\u0435, \u0441 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0441\u0438\u043c\u0444\u043e\u043d\u0438. \u0422\u043e\u0447\u043d\u0435\u0435, \u044f \u0445\u043e\u0447\u0443 \u0438\u043c\u0435\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043d\u0435\u0439, \u043d\u043e \u0438 \u0441 \u0434\u0440\u0443\u0433\u0438\u043c\u0438 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u0430\u043c\u0430\u043c\u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438. \u0421\u0435\u0433\u043e\u0434\u043d\u044f \u043c\u044b \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u0441 \u0434\u043e\u043a\u0442\u0440\u0438\u043d\u043e\u0439, \u0430 \u0437\u0430\u0432\u0442\u0440\u0430 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u043d\u0430 csv \u0444\u0430\u0439\u043b\u044b (\u0434\u0430, \u043a\u0435\u0439\u0441 \u043a\u043e\u0441\u043c\u0438\u0447\u0435\u0441\u043a\u0438\u0439, \u043d\u043e \u0442\u0430\u043a\u043e\u0435 \u0442\u043e\u0436\u0435 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c). \u041d\u0435 \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u0436\u0435 \u0432\u0435\u0441\u044c \u043f\u0440\u043e\u0435\u043a\u0442 \u0437\u0430\u043d\u043e\u0432\u043e?<\/p>\n<p>\u041f\u043e \u044d\u0442\u043e\u043c\u0443 \u043d\u0430\u043c \u043d\u0443\u0436\u0435\u043d \u043a\u0430\u043a\u043e\u0439 \u0442\u043e \u043d\u0430\u0431\u043e\u0440 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 \u043d\u0430\u0448\u0438\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u043c\u0438. \u0422\u0430\u043a\u043e\u0439 \u043d\u0430\u0431\u043e\u0440 \u043a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e \u0432\u044b\u043d\u043e\u0441\u0438\u0442\u0441\u044f \u0432 API \u0444\u0438\u0447\u0443. \u041f\u043e \u044d\u0442\u043e\u043c\u0443 \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c DataManagerFeatureApi, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u043f\u043e\u0440\u0442\u044b \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438.<\/p>\n<p>\u0418 \u0442\u0430\u043a, \u0447\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0432\u043d\u0443\u0442\u0440\u0438 \u044d\u0442\u043e\u0439 \u0444\u0438\u0447\u0438:<\/p>\n<ul>\n<li>\n<p>DTORequest \u2013 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u043c\u043e\u0434\u0443\u043b\u044c.<\/p>\n<\/li>\n<li>\n<p>DTORequestFactory \u2013 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0444\u0430\u0431\u0440\u0438\u043a<\/p>\n<\/li>\n<li>\n<p>DTOResponse \u2013 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0440\u0435\u0441\u043f\u043e\u043d\u0441 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0434\u043b\u044f \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0445 \u043c\u043e\u0434\u0443\u043b\u0435\u0439 \/ \u0444\u0438\u0447<\/p>\n<\/li>\n<li>\n<p>Service \u2013  \u0441\u043f\u0438\u0441\u043e\u043a \u201c\u043e\u0442\u043a\u0440\u044b\u0442\u044b\u0445\u201d \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0434\u043b\u044f \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0445 \u043c\u043e\u0434\u0443\u043b\u0435\u0439 \u0434\u043b\u044f \u043c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0446\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 (\u043f\u0440\u0438\u043c, \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438).<\/p>\n<\/li>\n<\/ul>\n<p>                                               \u041d\u0430\u0433\u043b\u044f\u0434\u043d\u044b\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 \u0438\u0437 \u043f\u0440\u043e\u0435\u043a\u0442\u0430:<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/7f7\/dfd\/19d\/7f7dfd19dc207c733cca37735ea8e9c9.png\" width=\"385\" height=\"316\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/7f7\/dfd\/19d\/7f7dfd19dc207c733cca37735ea8e9c9.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u0432 \u043f\u0440\u0438\u043b\u0430\u0433\u0430\u0435\u0442\u0441\u044f:<\/p>\n<details class=\"spoiler\">\n<summary>CategoryDataRequestInterface &#8212;  \u0440\u0435\u043a\u0432\u0435\u0441\u0442 \u043e\u0431\u044a\u0435\u043a\u0442 \u0434\u043b\u044f \u043c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0446\u0438\u0438 \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u0432 DataStorage<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\DataManagerFeatureApi\\DTORequest;  \/**  * @api  * Interface CategoryDataRequestInterface  * @package App\\DataManagerFeatureApi\\DTORequest  *  * Request object for a category creation  *  * WARNING! API DOESN'T know anything about realization!  * This interfaces provides public access for other features to a feature realization.  **\/ interface CategoryDataRequestInterface {     \/**      * @return int|null      *\/     public function getId(): ?int;      \/**      * @param int|null $id      *\/     public function setId(int $id = null): void;      \/**      * @return string|null      *\/     public function getTitle(): ?string;      \/**      * @param string|null $title      *\/     public function setTitle(string $title = null): void;      \/**      * @return string|null      *\/     public function getContent(): ?string;      \/**      * @param string|null $content      *\/     public function setContent(string $content = null): void;      \/**      * @return string|null      *\/     public function getSlug(): ?string;      \/**      * @param string|null $slug      *\/     public function setSlug(string $slug = null): void;      \/**      * @return bool      *\/     public function isActive(): bool;      \/**      * @param bool $active      *\/     public function setActive(bool $active): void; } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>PostDataRequestInterface &#8212;  \u0440\u0435\u043a\u0432\u0435\u0441\u0442 \u043e\u0431\u044a\u0435\u043a\u0442 \u0434\u043b\u044f \u043c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0446\u0438\u0438 \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u0432 DataStorage<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\DataManagerFeatureApi\\DTORequest;  \/**  * @api  * Interface PostDataRequestInterface  * @package App\\DataManagerFeatureApi\\DTORequest  *  * Request object for a post creation  *  * WARNING! API DOESN'T know anything about realization!  * This interfaces provides public access for other features to a feature realization.  *\/ interface PostDataRequestInterface {     \/**      * @return int|null      *\/     public function getId(): ?int;      \/**      * @param int|null $id      *\/     public function setId(int $id = null): void;      \/**      * @return string|null      *\/     public function getTitle(): ?string;      \/**      * @param string|null $title      *\/     public function setTitle(string $title = null): void;      \/**      * @return string|null      *\/     public function getContent(): ?string;      \/**      * @param string|null $content      *\/     public function setContent(string $content = null): void;      \/**      * @return string|null      *\/     public function getSlug(): ?string;      \/**      * @param string|null $slug      *\/     public function setSlug(string $slug = null): void;      \/**      * @return bool      *\/     public function isPublished(): bool;      \/**      * @param bool $published      *\/     public function setPublished(bool $published): void;      \/**      * @param int|null $id      * @return void      *\/     public function setCategoryId(int $id = null): void;      \/**      * @return int|null      *\/     public function getCategoryId(): ?int; } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>CategoryDataRequestFactoryInterface &#8212;  \u043f\u0440\u043e\u0441\u0442\u043e \u0444\u0430\u0431\u0440\u0438\u043a\u0430 \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0440\u0435\u043a\u0432\u0435\u0441\u0442\u0430<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\DataManagerFeatureApi\\DTORequestFactory;  use App\\DataManagerFeatureApi\\DTORequest\\CategoryDataRequestInterface;  \/**  * @api  * Interface CategoryDataRequestFactoryInterface  * @package App\\DataManagerFeatureApi\\DTORequestFactory  *  * WARNING! API DOESN'T know anything about realization!  * This interfaces provides public access for other features to a feature realization.  **\/ interface CategoryDataRequestFactoryInterface {     \/**      * @return CategoryDataRequestInterface      *\/     public function create(): CategoryDataRequestInterface; } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>PostDataRequestFactoryInterface &#8212; \u043f\u0440\u043e\u0441\u0442\u043e \u0444\u0430\u0431\u0440\u0438\u043a\u0430 \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0440\u0435\u043a\u0432\u0435\u0441\u0442\u0430<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\DataManagerFeatureApi\\DTORequestFactory;  use App\\DataManagerFeatureApi\\DTORequest\\PostDataRequestInterface;  \/**  * @api  * Interface PostDataRequestFactoryInterface  * @package App\\DataManagerFeatureApi\\DTORequestFactory  *  * WARNING! API DOESN'T know anything about realization!  * This interfaces provides public access for other features to a feature realization.  *\/ interface PostDataRequestFactoryInterface {     \/**      * @return PostDataRequestInterface      *\/     public function create(): PostDataRequestInterface; } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>CategoryDataResponseInterface &#8212; \u0440\u0435\u0441\u043f\u043e\u043d\u0441 \u043e\u0431\u044a\u0435\u043a\u0442 \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0439, \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0439 \u0434\u0440\u0443\u0433\u0438\u043c \u0444\u0438\u0447\u0430\u043c<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\DataManagerFeatureApi\\DTOResponse;  \/**  * @api  * Interface CategoryDataResponseInterface  * @package App\\DataManagerFeatureApi\\DTOResponse  *  * Module response object. This object will be returned for other features usage.  *  * WARNING! API DOESN'T know anything about realization!  * This interfaces provides public access for other features to a feature realization.  **\/ interface CategoryDataResponseInterface {     \/**      * @return int|null      *\/     public function getId(): ?int;      \/**      * @param int|null $id      *\/     public function setId(int $id = null): void;      \/**      * @return string|null      *\/     public function getTitle(): ?string;      \/**      * @param string|null $title      *\/     public function setTitle(string $title = null): void;      \/**      * @return string|null      *\/     public function getContent(): ?string;      \/**      * @param string|null $content      *\/     public function setContent(string $content = null): void;      \/**      * @return string      *\/     public function getSlug(): string;      \/**      * @param string|null $slug      *\/     public function setSlug(string $slug = null): void;      \/**      * @return bool      *\/     public function isActive(): bool;      \/**      * @param bool $active      *\/     public function setActive(bool $active): void; } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>PostDataResponseInterface &#8212; \u0440\u0435\u0441\u043f\u043e\u043d\u0441 \u043e\u0431\u044a\u0435\u043a\u0442 \u043f\u043e\u0441\u0442\u0430, \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0439 \u0434\u0440\u0443\u0433\u0438\u043c \u0444\u0438\u0447\u0430\u043c<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\DataManagerFeatureApi\\DTOResponse;  \/**  * @api  * Interface PostDataResponseInterface  * @package App\\DataManagerFeatureApi\\DTOResponse  *  * Module response object. This object will be returned for other features usage.  *  * WARNING! API DOESN'T know anything about realization!  * This interfaces provides public access for other features to a feature realization.  *\/ interface PostDataResponseInterface {     \/**      * @return int|null      *\/     public function getId(): ?int;      \/**      * @param int|null $id      *\/     public function setId(int $id = null): void;      \/**      * @return string|null      *\/     public function getTitle(): ?string;      \/**      * @param string|null $title      *\/     public function setTitle(string $title = null): void;      \/**      * @return string|null      *\/     public function getContent(): ?string;      \/**      * @param string|null $content      *\/     public function setContent(string $content = null): void;      \/**      * @return string|null      *\/     public function getSlug(): ?string;      \/**      * @param string|null $slug      *\/     public function setSlug(string $slug = null): void;      \/**      * @return bool      *\/     public function isPublished(): bool;      \/**      * @param bool $published      *\/     public function setPublished(bool $published): void;      \/**      * @return string|null      *\/     public function getUpdatedAt(): ?string;      \/**      * @param string|null $updatedAt      * @return void      *\/     public function setUpdatedAt(?string $updatedAt = null): void;      \/**      * @return string|null      *\/     public function getCreatedAt(): ?string;      \/**      * @param string|null $createdAt      * @return void      *\/     public function setCreatedAt(string $createdAt = null): void;      \/**      * @param int|null $id      * @return void      *\/     public function setCategoryId(int $id = null): void;      \/**      * @return int|null      *\/     public function getCategoryId(): ?int; } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>CategoryDataServiceInterface &#8212; \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0439<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\DataManagerFeatureApi\\Service;  use App\\DataManagerFeatureApi\\DTORequest\\CategoryDataRequestInterface; use App\\DataManagerFeatureApi\\DTOResponse\\CategoryDataResponseInterface;  \/**  * @api  * Interface CategoryDataServiceInterface  * @package App\\DataManagerFeatureApi\\Service  *  * Api service for categories management  *  * WARNING! API DOESN'T know anything about realization!  * This interfaces provides public access for other features to a feature realization.  **\/ interface CategoryDataServiceInterface {     \/**      * @param array|null $criteria      * @return array      *\/     public function getList(array $criteria = null): array;      \/**      * @param int $categoryId      * @return CategoryDataResponseInterface|null      *\/     public function getById(int $categoryId): ?CategoryDataResponseInterface;      \/**      * @param CategoryDataRequestInterface $dtoRequest      * @return CategoryDataResponseInterface      *\/     public function save(CategoryDataRequestInterface $dtoRequest): CategoryDataResponseInterface;      \/**      * @param int $id      * @return void      *\/     public function deleteById(int $id): void;      \/**      * @param string $slug      * @return CategoryDataResponseInterface|null      *\/     public function getBySlug(string $slug): ?CategoryDataResponseInterface; } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>PostDataServiceInterface &#8212; \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u0434\u043b\u044f \u043f\u043e\u0441\u0442\u043e\u0432<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\DataManagerFeatureApi\\Service;  use App\\DataManagerFeatureApi\\DTORequest\\PostDataRequestInterface; use App\\DataManagerFeatureApi\\DTOResponse\\PostDataResponseInterface;  \/**  * @api  * Interface PostDataServiceInterface  * @package App\\DataManagerFeatureApi\\Service  *  * Api service for posts management  *  * WARNING! API DOESN'T know anything about realization!  * This interfaces provides public access for other features to a feature realization.  *\/ interface PostDataServiceInterface {     \/**      * @param array|null $criteria      * @return array      *\/     public function getList(array $criteria = null): array;      \/**      * @param int $postId      * @return PostDataResponseInterface|null      *\/     public function getById(int $postId): ?PostDataResponseInterface;      \/**      * @param PostDataRequestInterface $dtoRequest      * @return PostDataResponseInterface      *\/     public function save(PostDataRequestInterface $dtoRequest): PostDataResponseInterface;      \/**      * @param int $id      * @return void      *\/     public function deleteById(int $id): void;      \/**      * @param string $slug      * @return PostDataResponseInterface|null      *\/     public function getBySlug(string $slug): ?PostDataResponseInterface; } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u043a \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0439 \u043c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0446\u0438\u0438 \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438. \u042f \u0431\u0443\u0434\u0443 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0447\u0435\u0440\u0435\u0437 \u0434\u043e\u043a\u0442\u0440\u0438\u043d\u0443.<\/p>\n<h3>DoctrineDataFeature (implements DataManagerFeatureApi)<\/h3>\n<p><a class=\"anchor\" name=\"doctrineFeature\" id=\"doctrineFeature\"><\/a><\/p>\n<p>\u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0441\u043e\u0437\u0434\u0430\u0442\u044c EloquentFeature,  \u043a\u0430\u043a \u043f\u0440\u0438\u043c\u0435\u0440, \u0435\u0441\u043b\u0438 \u043d\u0435 \u0445\u043e\u0442\u0438\u0442\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u0434\u043e\u043a\u0442\u0440\u0438\u043d\u043e\u0439. \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0438\u043c\u0435\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e DataManagerFeatures \u0438 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u0442\u044c\u0441\u044f \u043c\u0435\u0436\u0434\u0443 \u043d\u0438\u043c\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f DI (dependecy injection). \u0412 \u044d\u0442\u043e\u043c \u0438 \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u0435\u043b\u0435\u0441\u0442\u044c \u0447\u0438\u0441\u0442\u043e\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b \u0441 \u0440\u0430\u0437\u0431\u0438\u0432\u043a\u043e\u0439 \u043f\u043e \u0444\u0438\u0447\u0430\u043c.<\/p>\n<p>\u0414\u0430\u043d\u043d\u0430\u044f \u0444\u0438\u0447\u0430 \u0443 \u043d\u0430\u0441 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442 <strong>DataManagerFeatureApi. <\/strong><em>\u041f\u0440\u043e\u0448\u0443 \u0437\u0430\u043c\u0435\u0442\u0438\u0442\u044c<\/em>, \u0447\u0442\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f API  \u043c\u043e\u0434\u0443\u043b\u0435\u0439 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 Application \u0441\u043b\u043e\u0435 \u043a\u0430\u0436\u0434\u043e\u0439 \u0444\u0438\u0447\u0438. \u0418\u043c\u0435\u043d\u043d\u043e \u0434\u0430\u043d\u043d\u044b\u0439 \u0441\u043b\u043e\u0439 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043f\u043e\u0441\u043b\u0435 input\/output.<\/p>\n<p>\u041a\u0430\u043a \u044f \u0443\u0436\u0435 \u0433\u043e\u0432\u043e\u0440\u0438\u043b\u0430, \u043a\u0430\u0436\u0434\u0430\u044f \u0444\u0438\u0447\u0430 \u0438\u043c\u0435\u0435\u0442 \u043f\u0440\u0430\u0432\u043e \u043d\u0435 \u0438\u043c\u0435\u0442\u044c \u0432\u0441\u0435 \u0441\u043b\u043e\u0438, \u043e\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0435 \u0432\u044b\u0448\u0435. \u0412 \u044d\u0442\u043e\u0439 \u0444\u0438\u0447\u0435 \u0438\u0434\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430 \u0441 \u043c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0446\u0438\u0435\u0439 \u0434\u0430\u043d\u043d\u044b\u0445, \u043d\u0430\u043c \u043d\u0435 \u043d\u0443\u0436\u0435\u043d \u0437\u0434\u0435\u0441\u044c Presentation layer.<\/p>\n<p>\u0421\u043f\u0438\u0441\u043e\u043a \u0441\u043b\u043e\u0435\u0432:<\/p>\n<ul>\n<li>\n<p><strong>Application<\/strong> \u2013 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u201crequested data\u201d \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0442 \u0440\u0435\u0441\u043f\u043e\u043d\u0441\u0430. \u041a\u043b\u0430\u0441\u0441\u044b \u0441 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0441\u043b\u043e\u044f \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u043d\u044b \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u043c\u0438 \u043c\u043e\u0434\u0443\u043b\u044f\u043c\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f API feature (\u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 <strong>DataManagerFeatureApi )<\/strong><\/p>\n<\/li>\n<li>\n<p><strong>Domain<\/strong> \u2013 \u0437\u0430\u0449\u0438\u0449\u0435\u043d\u043d\u044b\u0435 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 \u043e\u0442 \u0432\u043d\u0435\u0448\u043d\u0435\u0433\u043e \u043c\u0438\u0440\u0430<\/p>\n<\/li>\n<li>\n<p><strong>Infrastructure<\/strong> \u2013 \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0434\u043e\u043a\u0442\u0440\u0438\u043d\u043e\u0439<\/p>\n<\/li>\n<\/ul>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/6a6\/6ab\/d76\/6a66abd762f75d33580d5e46a1b5bc0f.png\" alt=\"\u0412\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0437\u0434\u0435\u0441\u044c \u0431\u0443\u0434\u0435\u0442 \u043c\u043d\u043e\u0433\u043e \u043a\u043b\u0430\u0441\u0441\u043e\u0432. \u041f\u0440\u0438\u0432\u043e\u0436\u0443 \u0434\u043b\u044f \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e\u0441\u0442\u0438 \u043f\u0440\u0438\u043c\u0435\u0440 \u0438\u0437 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\" title=\"\u0412\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0437\u0434\u0435\u0441\u044c \u0431\u0443\u0434\u0435\u0442 \u043c\u043d\u043e\u0433\u043e \u043a\u043b\u0430\u0441\u0441\u043e\u0432. \u041f\u0440\u0438\u0432\u043e\u0436\u0443 \u0434\u043b\u044f \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e\u0441\u0442\u0438 \u043f\u0440\u0438\u043c\u0435\u0440 \u0438\u0437 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\" width=\"1430\" height=\"797\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/6a6\/6ab\/d76\/6a66abd762f75d33580d5e46a1b5bc0f.png\"\/><figcaption>\u0412\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0437\u0434\u0435\u0441\u044c \u0431\u0443\u0434\u0435\u0442 \u043c\u043d\u043e\u0433\u043e \u043a\u043b\u0430\u0441\u0441\u043e\u0432. \u041f\u0440\u0438\u0432\u043e\u0436\u0443 \u0434\u043b\u044f \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e\u0441\u0442\u0438 \u043f\u0440\u0438\u043c\u0435\u0440 \u0438\u0437 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/figcaption><\/figure>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043a\u043e\u0434 \u0432 \u0434\u0435\u0442\u0430\u043b\u044f\u0445.<\/p>\n<p>\u0412\u0441\u0435\u0434\u0430 \u043d\u0430\u0447\u0438\u043d\u0430\u044e \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 \u0432\u044b\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0434\u043e\u043c\u0435\u043d\u043d\u043e\u0433\u043e \u0441\u043b\u043e\u044f, \u0430 \u0437\u0430\u0442\u0435\u043c \u043f\u0435\u0440\u0435\u0445\u043e\u0436\u0443 \u043a \u0434\u0440\u0443\u0433\u0438\u043c \u0441\u043b\u043e\u044f\u043c.<\/p>\n<hr\/>\n<h3>Domain layer<\/h3>\n<p><strong>Domain layer (Entity) &#8212; <\/strong>\u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0435\u0439 \u0434\u043e\u043a\u0442\u0440\u0438\u043d\u044b. \u0412\u0430\u0436\u043d\u043e \u043f\u043e\u043c\u043d\u0438\u0442\u044c, \u0447\u0442\u043e \u0432\u0441\u0435, \u0447\u0442\u043e \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u0434\u043e\u043c\u0435\u043d\u0435 \u043d\u0438 \u0432 \u043a\u043e\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043d\u0435 \u043e\u0442\u0434\u0430\u0435\u0442\u0441\u044f \u043d\u0430\u0440\u0443\u0436\u0443! \u0422\u043a \u044d\u0442\u0430 \u0444\u0438\u0447\u0430 \u0443 \u043d\u0430\u0441 \u0441\u043e\u0437\u0434\u0430\u043d\u0430 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0434\u043e\u043a\u0442\u0440\u0438\u043d\u043e\u0439, \u0442\u043e \u0438 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 \u0441\u043e\u0437\u0434\u0430\u044e\u0442\u0441\u044f \u0441 \u043f\u0440\u0438\u0432\u044f\u0437\u043a\u043e\u0439 \u043a \u043d\u0435\u0439.<\/p>\n<details class=\"spoiler\">\n<summary>Category<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\DoctrineDataFeature\\Domain\\Entity;  use App\\DoctrineDataFeature\\Infrastructure\\Repository\\CategoryRepository; use Doctrine\\DBAL\\Types\\Types; use Doctrine\\ORM\\Mapping as ORM;  \/**  * Class Category  * Doctrine entity determination  *  * @package App\\DoctrineDataFeature\\Infrastructure\\Entity\\Doctrine  *\/ #[ORM\\Entity(repositoryClass: CategoryRepository::class)] class Category {     #[ORM\\Id]     #[ORM\\GeneratedValue]     #[ORM\\Column]     private ?int $id = null;      #[ORM\\Column(length: 255)]     private ?string $title = null;      #[ORM\\Column(type: Types::TEXT, nullable: true)]     private ?string $content = null;      #[ORM\\Column(length: 255, unique: true)]     private ?string $slug = null;      #[ORM\\Column]     private bool $isActive = false;      \/**      * @param int|null $id      *\/     public function setId(?int $id): void     {         $this->id = $id;     }      \/**      * @return int|null      *\/     public function getId(): ?int     {         return $this->id;     }      \/**      * @return string|null      *\/     public function getTitle(): ?string     {         return $this->title;     }      \/**      * @param string $title      * @return $this      *\/     public function setTitle(string $title): self     {         $this->title = $title;         return $this;     }      \/**      * @return string|null      *\/     public function getContent(): ?string     {         return $this->content;     }      \/**      * @param string|null $content      * @return $this      *\/     public function setContent(?string $content): self     {         $this->content = $content;         return $this;     }      \/**      * @return string|null      *\/     public function getSlug(): ?string     {         return $this->slug;     }      \/**      * @param string $slug      * @return $this      *\/     public function setSlug(string $slug): self     {         $this->slug = $slug;         return $this;     }      \/**      * @return bool      *\/     public function getIsActive(): bool     {         return $this->isActive;     }      \/**      * @param bool $active      * @return $this      *\/     public function setActive(bool $active): self     {         $this->isActive = $active;         return $this;     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>Post<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\DoctrineDataFeature\\Domain\\Entity;  use App\\DoctrineDataFeature\\Infrastructure\\Repository\\PostRepository; use DateTime; use DateTimeInterface; use Doctrine\\DBAL\\Types\\Types; use Doctrine\\ORM\\Mapping as ORM;  \/**  * Class Post  * Doctrine entity determination  *  * @package App\\DoctrineDataFeature\\Domain\\Entity  *\/ #[ORM\\Entity(repositoryClass: PostRepository::class)] #[ORM\\HasLifecycleCallbacks] class Post {     #[ORM\\Id]     #[ORM\\GeneratedValue]     #[ORM\\Column]     private ?int $id = null;      #[ORM\\Column(length: 255)]     private ?string $title = null;      #[ORM\\Column(type: Types::TEXT, nullable: true)]     private ?string $content = null;      #[ORM\\Column(length: 255, unique: true)]     private ?string $slug = null;      #[ORM\\Column]     private bool $isPublished = false;      #[ORM\\Column(type: \"datetime\", nullable: true)]     private ?DateTimeInterface $createdAt = null;      #[ORM\\Column(type: \"datetime\", nullable: true)]     private ?DateTimeInterface $updatedAt = null;      #[ORM\\ManyToOne(targetEntity: Category::class, inversedBy: 'posts')]     private Category|null $category = null;      \/**      * @param int|null $id      *\/     public function setId(?int $id): void     {         $this->id = $id;     }      \/**      * @return int|null      *\/     public function getId(): ?int     {         return $this->id;     }      \/**      * @return string|null      *\/     public function getTitle(): ?string     {         return $this->title;     }      \/**      * @param string $title      * @return $this      *\/     public function setTitle(string $title): self     {         $this->title = $title;         return $this;     }      \/**      * @return string|null      *\/     public function getContent(): ?string     {         return $this->content;     }      \/**      * @param string|null $content      * @return $this      *\/     public function setContent(?string $content): self     {         $this->content = $content;         return $this;     }      \/**      * @return string|null      *\/     public function getSlug(): ?string     {         return $this->slug;     }      \/**      * @param string $slug      * @return $this      *\/     public function setSlug(string $slug): self     {         $this->slug = $slug;         return $this;     }      \/**      * @return bool      *\/     public function isPublished(): bool     {         return $this->isPublished;     }      \/**      * @param bool $published      * @return $this      *\/     public function setPublished(bool $published): self     {         $this->isPublished = $published;         return $this;     }      \/**      * @return Category|null      *\/     public function getCategory(): ?Category     {         return $this->category;     }      \/**      * @param Category|null $category      * @return Post      *\/     public function setCategory(?Category $category): self     {         $this->category = $category;         return $this;     }      \/**      * @return DateTimeInterface|null      *\/     public function getCreatedAt(): ?DateTimeInterface     {         return $this->createdAt;     }      \/**      * @param DateTimeInterface|null $timestamp      * @return $this      *\/     public function setCreatedAt(?DateTimeInterface $timestamp): self     {         $this->createdAt = $timestamp;         return $this;     }      \/**      * @return DateTimeInterface|null      *\/     public function getUpdatedAt(): ?DateTimeInterface     {         return $this->updatedAt;     }      \/**      * @param DateTimeInterface|null $timestamp      * @return $this      *\/     public function setUpdatedAt(?DateTimeInterface $timestamp): self     {         $this->updatedAt = $timestamp;         return $this;     }      #[ORM\\PrePersist]     #[ORM\\PreUpdate]     \/**      * @return void      *\/     protected function updateTimestamps(): void     {         $dateTimeNow = new DateTime('now');          $this->setUpdatedAt($dateTimeNow);          if ($this->getCreatedAt() === null) {             $this->setCreatedAt($dateTimeNow);         }     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p><strong>Domain layer (Repository)<\/strong> &#8212; \u0432\u0430\u0436\u043d\u043e! \u0432 \u0434\u043e\u043c\u0435\u043d\u0435 \u043d\u0438\u043a\u043e\u0433\u0434\u0430 \u043d\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u044e\u0442\u0441\u044f \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438. \u0417\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u043e\u0442\u0432\u0435\u0447\u0430\u0442\u0435 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043d\u044b\u0439 \u0441\u043b\u043e\u0439.<\/p>\n<details class=\"spoiler\">\n<summary>CategoryRepositoryInterface<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\DoctrineDataFeature\\Domain\\Repository;  use App\\DoctrineDataFeature\\Domain\\Entity\\Category;  \/**  * Interface CategoryRepositoryInterface  * @package App\\DoctrineDataFeature\\Domain\\Repository  *  * Domain layer NEVER implements repository. Domain doesn't know anything about data storages.  * Domain uses behavior description, repository must be implemented in Infrastructure layer according to a source  * (eg. DB, Session and so on)  **\/ interface CategoryRepositoryInterface {     \/**      * @param Category $category      * @return Category      *\/     public function save(Category $category): Category;      \/**      * @param array|null $criteria      * @return array      *\/     public function getList(array $criteria = null): array;      \/**      * @param int $id      * @return object|null      *\/     public function getById(int $id): ?object;      \/**      * @param int $id      * @return void      *\/     public function deleteById(int $id): void;      \/**      * @param object $category      * @return void      *\/     public function delete(object $category): void;      \/**      * @param string $slug      * @return object|null      *\/     public function getBySlug(string $slug): ?object; } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>PostRepositoryInterface<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\DoctrineDataFeature\\Domain\\Repository;  use App\\DoctrineDataFeature\\Domain\\Entity\\Post;  \/**  * Interface PostRepositoryInterface  * @package App\\DoctrineDataFeature\\Domain\\Repository  *  * Domain layer NEVER implements repository. Domain doesn't know anything about data storages.  * Domain uses behavior description, repository must be implemented in Infrastructure layer according to a source  * (eg. DB, Session and so on)  *\/ interface PostRepositoryInterface {     \/**      * @param Post $post      * @return Post      *\/     public function save(Post $post): Post;      \/**      * @param array|null $criteria      * @return array      *\/     public function getList(array $criteria = null): array;      \/**      * @param int $id      * @return object|null      *\/     public function getById(int $id): ?object;      \/**      * @param int $id      * @return void      *\/     public function deleteById(int $id): void;      \/**      * @param object $post      * @return void      *\/     public function delete(object $post): void;      \/**      * @param string $slug      * @return object|null      *\/     public function getBySlug(string $slug): ?object; } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0441\u043f\u0443\u0441\u0442\u0438\u043c\u0441\u044f \u0435\u0449\u0435 \u043d\u0430 \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u043d\u0438\u0436\u0435 \u0438 \u043e\u043f\u0438\u0448\u0435\u043c \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0443\u043a\u0442\u0443\u0440\u043d\u044b\u0439 \u0441\u043b\u043e\u0439.<\/p>\n<hr\/>\n<h3>Infrastructure layer<\/h3>\n<p><strong>Infrastructure layer (Repository)<\/strong> &#8212; \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0435\u0432<\/p>\n<details class=\"spoiler\">\n<summary>CategoryRepository<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\DoctrineDataFeature\\Infrastructure\\Repository;  use App\\DoctrineDataFeature\\Domain\\Entity\\Category; use App\\DoctrineDataFeature\\Domain\\Repository\\CategoryRepositoryInterface; use Doctrine\\Bundle\\DoctrineBundle\\Repository\\ServiceEntityRepository; use Doctrine\\ORM\\NonUniqueResultException; use Doctrine\\Persistence\\ManagerRegistry; use InvalidArgumentException; use Symfony\\Component\\HttpKernel\\Exception\\NotFoundHttpException;  \/**  * Class CategoryRepository  * Work directly with data storage  *  * @package App\\DoctrineDataFeature\\Infrastructure\\Persistence\\Doctrine  *  * @method Category|null find($id, $lockMode = null, $lockVersion = null)  * @method Category|null findOneBy(array $criteria, array $orderBy = null)  * @method Category[]    findAll()  * @method Category[]    findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)  **\/ class CategoryRepository extends ServiceEntityRepository implements CategoryRepositoryInterface {     \/**      * @param ManagerRegistry $registry      *\/     public function __construct(ManagerRegistry $registry)     {         parent::__construct($registry, Category::class);     }      \/**      * @param Category $category      * @return Category      *\/     public function save(Category $category): Category     {         if ($category->getId()) {             $this->_em->merge($category);         } else {             $this->_em->persist($category);         }          $this->_em->flush();          return $category;     }      \/**      * @return object[]      *\/     public function getList(array $criteria = null): array     {         if (!$criteria) {             return $this->findAll();         }          return $this->findBy($criteria);     }      \/**      * @param int $id      * @return Category|null      *\/     public function getById(int $id): ?Category     {         return $this->find($id);     }      \/**      * @param string $slug      * @return object|null      * @throws NonUniqueResultException      *\/     public function getBySlug(string $slug): ?object     {         $qb = $this->createQueryBuilder('q')             ->where('q.slug = :slug')             ->setParameter('slug', $slug);          $query = $qb->getQuery();          return $query->setMaxResults(1)->getOneOrNullResult();     }      \/**      * @param int $id      * @return void      *\/     public function deleteById(int $id): void     {         $category = $this->find($id);          if (!$category) {             throw new NotFoundHttpException(sprintf(\"The category with ID '%s' doesn't exist\", $id));         }          $this->delete($category);     }      \/**      * @param object $category      * @return void      *\/     public function delete(object $category): void     {         if (!$category instanceof Category) {             throw new InvalidArgumentException(                 sprintf('You can only pass %s entity to this repository.', Category::class)             );         }          $this->_em->remove($category);         $this->_em->flush();     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>PostRepository<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\DoctrineDataFeature\\Infrastructure\\Repository;  use App\\DoctrineDataFeature\\Domain\\Entity\\Post; use App\\DoctrineDataFeature\\Domain\\Repository\\PostRepositoryInterface; use Doctrine\\Bundle\\DoctrineBundle\\Repository\\ServiceEntityRepository; use Doctrine\\ORM\\NonUniqueResultException; use Doctrine\\Persistence\\ManagerRegistry; use InvalidArgumentException; use Symfony\\Component\\HttpKernel\\Exception\\NotFoundHttpException;  \/**  * Class PostRepository  * Work directly with data storage  *  * @package App\\DoctrineDataFeature\\Infrastructure\\Repository  *  * @method Post|null find($id, $lockMode = null, $lockVersion = null)  * @method Post|null findOneBy(array $criteria, array $orderBy = null)  * @method Post[]    findAll()  * @method Post[]    findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)  *\/ class PostRepository extends ServiceEntityRepository implements PostRepositoryInterface {     \/**      * @param ManagerRegistry $registry      *\/     public function __construct(ManagerRegistry $registry)     {         parent::__construct($registry, Post::class);     }      \/**      * @param Post $post      * @return Post      *\/     public function save(Post $post): Post     {         if ($post->getId()) {             $this->_em->merge($post);         } else {             $this->_em->persist($post);         }          $this->_em->flush();          return $post;     }      \/**      * @return object[]      *\/     public function getList(array $criteria = null): array     {         if (!$criteria) {             return $this->findAll();         }          return $this->findBy($criteria);     }      \/**      * @param int $id      * @return Post|null      *\/     public function getById(int $id): ?Post     {         return $this->find($id);     }      \/**      * @param string $slug      * @return object|null      * @throws NonUniqueResultException      *\/     public function getBySlug(string $slug): ?object     {         $qb = $this->createQueryBuilder('q')             ->where('q.slug = :slug')             ->setParameter('slug', $slug);          $query = $qb->getQuery();          return $query->setMaxResults(1)->getOneOrNullResult();     }      \/**      * @param int $id      * @return void      *\/     public function deleteById(int $id): void     {         $post = $this->find($id);          if (!$post) {             throw new NotFoundHttpException(sprintf(\"The post with ID '%s' doesn't exist\", $id));         }          $this->delete($post);     }      \/**      * @param object $post      * @return void      *\/     public function delete(object $post): void     {         if (!$post instanceof Post) {             throw new InvalidArgumentException(                 sprintf('You can only pass %s entity to this repository.', Post::class)             );         }          $this->_em->remove($post);         $this->_em->flush();     } } <\/code><\/pre>\n<\/p>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041f\u043e\u0441\u043b\u0435 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0434\u043e\u043c\u0435\u043d\u0430 \u0438 \u0440\u0430\u0431\u043e\u0442\u044b (\u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435) \u0441 \u0431\u0430\u0437\u043e\u0439 \u0434\u0430\u043d\u043d\u044b\u0445, \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c \u043a \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u043c\u043e\u0434\u0443\u043b\u044f \u0441 \u0440\u0435\u043a\u0432\u0435\u0441\u0442 \u043e\u0431\u044a\u0435\u043a\u0442\u0430\u043c\u0438.<\/p>\n<hr\/>\n<h3>Application layer<\/h3>\n<p><strong>Application layer (ApiService) &#8212; <\/strong>\u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u0434\u043b\u044f \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0445 \u043c\u043e\u0434\u0443\u043b\u0435\u0439 (\u0444\u0438\u0447). \u0417\u0434\u0435\u0441\u044c \u043d\u0430 \u0432\u0445\u043e\u0434 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442\u0441\u044f ResponseDTO \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f RequestDTO<\/p>\n<details class=\"spoiler\">\n<summary>CategoryService<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\DoctrineDataFeature\\Application\\ApiService;  use App\\DataManagerFeatureApi\\DTORequest\\CategoryDataRequestInterface; use App\\DataManagerFeatureApi\\DTOResponse\\CategoryDataResponseInterface; use App\\DataManagerFeatureApi\\Service\\CategoryDataServiceInterface; use App\\DoctrineDataFeature\\Application\\DataMapper\\DataMapperInterface; use App\\DoctrineDataFeature\\Domain\\Repository\\CategoryRepositoryInterface;  \/**  * Class CategoryService  * @package App\\DoctrineDataFeature\\Application\\ApiService  *  * This class is for external usage (outside this feature) only  * Use CategoryDataServiceInterface for data manipulating and return DTOResponse here  *  * Don't return Domain entity outside the feature!  **\/ class CategoryService implements CategoryDataServiceInterface {     private DataMapperInterface $dataMapper;     private CategoryRepositoryInterface $categoryRepository;      \/**      * Use DI for injecting appropriate objects here      * @param DataMapperInterface $dataMapper      * @param CategoryRepositoryInterface $categoryRepository      *\/     public function __construct(         DataMapperInterface $dataMapper,         CategoryRepositoryInterface $categoryRepository     ) {         $this->dataMapper = $dataMapper;         $this->categoryRepository = $categoryRepository;     }      \/**      * @param array|null $criteria      * @return array      *\/     public function getList(array $criteria = null): array     {         $list = [];         $result = $this->categoryRepository->getList($criteria);          foreach ($result as $item) {             $list[] = $this->dataMapper->toResponse($item);         }          return $list;     }      \/**      * @param int $categoryId      * @return CategoryDataResponseInterface|null      *\/     public function getById(int $categoryId): ?CategoryDataResponseInterface     {         $entity = $this->categoryRepository->getById($categoryId);         return $entity ? $this->dataMapper->toResponse($entity) : null;     }      \/**      * @param CategoryDataRequestInterface $dtoRequest      * @return CategoryDataResponseInterface      *\/     public function save(CategoryDataRequestInterface $dtoRequest): CategoryDataResponseInterface     {         $entity = $this->dataMapper->toEntity($dtoRequest);         $this->categoryRepository->save($entity);          return $this->dataMapper->toResponse($entity);     }      \/**      * @param int $id      * @return void      *\/     public function deleteById(int $id): void     {         $this->categoryRepository->deleteById($id);     }      \/**      * @param string $slug      * @return CategoryDataResponseInterface|null      *\/     public function getBySlug(string $slug): ?CategoryDataResponseInterface     {         $entity = $this->categoryRepository->getBySlug($slug);         return $entity ? $this->dataMapper->toResponse($entity) : null;     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>PostService<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\DoctrineDataFeature\\Application\\ApiService;  use App\\DataManagerFeatureApi\\DTORequest\\PostDataRequestInterface; use App\\DataManagerFeatureApi\\DTOResponse\\PostDataResponseInterface; use App\\DataManagerFeatureApi\\Service\\PostDataServiceInterface; use App\\DoctrineDataFeature\\Application\\DataMapper\\DataMapperInterface; use App\\DoctrineDataFeature\\Domain\\Repository\\PostRepositoryInterface;  \/**  * Class PostService  * @package App\\DoctrineDataFeature\\Application\\ApiService  *  * This class is for external usage (outside this feature) only  * Use CategoryDataServiceInterface for data manipulating and return DTOResponse here  *  * Don't return Domain entity outside the feature!  *\/ class PostService implements PostDataServiceInterface {     private DataMapperInterface $dataMapper;     private PostRepositoryInterface $postRepository;      \/**      * @param DataMapperInterface $dataMapper      * @param PostRepositoryInterface $postRepository      *\/     public function __construct(         DataMapperInterface $dataMapper,         PostRepositoryInterface $postRepository     ) {         $this->dataMapper = $dataMapper;         $this->postRepository = $postRepository;     }      \/**      * @param array|null $criteria      * @return array      *\/     public function getList(array $criteria = null): array     {         $list = [];         $result = $this->postRepository->getList($criteria);          foreach ($result as $item) {             $list[] = $this->dataMapper->toResponse($item);         }          return $list;     }      \/**      * @param int $postId      * @return PostDataResponseInterface|null      *\/     public function getById(int $postId): ?PostDataResponseInterface     {         $entity = $this->postRepository->getById($postId);         return $entity ? $this->dataMapper->toResponse($entity) : null;     }      \/**      * @param PostDataRequestInterface $dtoRequest      * @return PostDataResponseInterface      *\/     public function save(PostDataRequestInterface $dtoRequest): PostDataResponseInterface     {         $entity = $this->dataMapper->toEntity($dtoRequest);         $this->postRepository->save($entity);          return $this->dataMapper->toResponse($entity);     }      \/**      * @param int $id      * @return void      *\/     public function deleteById(int $id): void     {         $this->postRepository->deleteById($id);     }      \/**      * @param string $slug      * @return PostDataResponseInterface|null      *\/     public function getBySlug(string $slug): ?PostDataResponseInterface     {         $entity = $this->postRepository->getBySlug($slug);         return $entity ? $this->dataMapper->toResponse($entity) : null;     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p><strong>Application layer (DataMapper) &#8212; <\/strong>\u0437\u0434\u0435\u0441\u044c \u043c\u0430\u043f\u043f\u0438\u043d\u0433 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0432 \u0440\u0435\u0441\u043f\u043e\u043d\u0441 \u0438\u043b\u0438 \u0434\u043e\u043c\u0435\u043d<\/p>\n<details class=\"spoiler\">\n<summary>DataMapperInterface &#8212; \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0435\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\DoctrineDataFeature\\Application\\DataMapper;  use App\\DoctrineDataFeature\\Application\\DTORequest\\DataRequestInterface; use App\\DoctrineDataFeature\\Application\\DTOResponse\\DataResponseInterface;  \/**  * Interface DataMapperInterface  * This is common interface for data mappers.  *  * @package App\\DoctrineDataFeature\\Application\\EntityMapper  **\/ interface DataMapperInterface {     \/**      * Map DTORequest object to Infrastructure entity      * @param DataRequestInterface $request      * @return object      *\/     public function toEntity(DataRequestInterface $request): object;      \/**      * Map entity to DTOResponse      * @param object $entity      * @return DataResponseInterface      *\/     public function toResponse(object $entity): DataResponseInterface; } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>CategoryMapper<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\DoctrineDataFeature\\Application\\DataMapper;  use App\\DataManagerFeatureApi\\DTORequest\\CategoryDataRequestInterface; use App\\DoctrineDataFeature\\Application\\DTORequest\\DataRequestInterface; use App\\DoctrineDataFeature\\Application\\DTOResponse\\DataResponseInterface; use App\\DoctrineDataFeature\\Application\\DTOResponseFactory\\CategoryResponseFactoryInterface; use App\\DoctrineDataFeature\\Domain\\Entity\\Category; use InvalidArgumentException;  \/**  * Class CategoryMapper  * @package App\\DoctrineDataFeature\\Application\\DTOEntityMapper  **\/ class CategoryMapper implements DataMapperInterface {     private CategoryResponseFactoryInterface $categoryResponseFactory;      \/**      * @param CategoryResponseFactoryInterface $categoryResponseFactory      *\/     public function __construct(CategoryResponseFactoryInterface $categoryResponseFactory)     {         $this->categoryResponseFactory = $categoryResponseFactory;     }      \/**      * Map DTORequest object to Infrastructure entity      * @param DataRequestInterface $request      * @return Category      *\/     public function toEntity(DataRequestInterface $request): Category     {         if (!$request instanceof CategoryDataRequestInterface) {             throw new InvalidArgumentException(                 sprintf('You can pass %s only to this mapper.', CategoryDataRequestInterface::class)             );         }          $doctrineEntity = new Category();          $doctrineEntity->setId($request->getId());         $doctrineEntity->setActive($request->isActive());         $doctrineEntity->setContent($request->getContent());         $doctrineEntity->setSlug($request->getSlug());         $doctrineEntity->setTitle($request->getTitle());          return $doctrineEntity;     }      \/**      * Map entity to DTOResponse      * @param object $entity      * @return DataResponseInterface      *\/     public function toResponse(object $entity): DataResponseInterface     {         if (!$entity instanceof Category) {             throw new InvalidArgumentException(                 sprintf('You can only pass %s entity to this mapper.', Category::class)             );         }          $response = $this->categoryResponseFactory->create();          $response->setId($entity->getId());         $response->setActive($entity->getIsActive());         $response->setContent($entity->getContent());         $response->setSlug($entity->getSlug());         $response->setTitle($entity->getTitle());          return $response;     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>PostMapper<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\DoctrineDataFeature\\Application\\DataMapper;  use App\\DataManagerFeatureApi\\DTORequest\\PostDataRequestInterface; use App\\DoctrineDataFeature\\Application\\DTORequest\\DataRequestInterface; use App\\DoctrineDataFeature\\Application\\DTOResponse\\DataResponseInterface; use App\\DoctrineDataFeature\\Application\\DTOResponseFactory\\PostResponseFactoryInterface; use App\\DoctrineDataFeature\\Domain\\Entity\\Category; use App\\DoctrineDataFeature\\Domain\\Entity\\Post; use App\\DoctrineDataFeature\\Domain\\Repository\\CategoryRepositoryInterface; use InvalidArgumentException; use Symfony\\Component\\HttpKernel\\Exception\\NotFoundHttpException;  \/**  * Class PostMapper  * @package App\\DoctrineDataFeature\\Application\\DataMapper  *\/ class PostMapper implements DataMapperInterface {     private PostResponseFactoryInterface $postResponseFactory;     private CategoryRepositoryInterface $categoryRepository;      \/**      * @param PostResponseFactoryInterface $postResponseFactory      * @param CategoryRepositoryInterface $categoryRepository      *\/     public function __construct(         PostResponseFactoryInterface $postResponseFactory,         CategoryRepositoryInterface $categoryRepository     ) {         $this->postResponseFactory = $postResponseFactory;         $this->categoryRepository = $categoryRepository;     }      \/**      * Map DTORequest object to Infrastructure entity      * @param DataRequestInterface $request      * @return object      *\/     public function toEntity(DataRequestInterface $request): object     {         if (!$request instanceof PostDataRequestInterface) {             throw new InvalidArgumentException(                 sprintf('You can pass %s only to this mapper.', PostDataRequestInterface::class)             );         }          $doctrineEntity = new Post();          $doctrineEntity->setId($request->getId());         $doctrineEntity->setPublished($request->isPublished());         $doctrineEntity->setContent($request->getContent());         $doctrineEntity->setSlug($request->getSlug());         $doctrineEntity->setTitle($request->getTitle());          if ($categoryId = $request->getCategoryId()) {             $category = $this->getCategory($categoryId);             $doctrineEntity->setCategory($category);         }          return $doctrineEntity;     }      \/**      * @param int $categoryId      * @return Category      *\/     private function getCategory(int $categoryId): Category     {         $category = $this->categoryRepository->getById($categoryId);          if (!$category) {             throw new NotFoundHttpException(sprintf(\"The category with ID '%s' doesn't exist\", $category));         }          return $category;     }      \/**      * Map entity to DTOResponse      * @param object $entity      * @return DataResponseInterface      *\/     public function toResponse(object $entity): DataResponseInterface     {         if (!$entity instanceof Post) {             throw new InvalidArgumentException(                 sprintf('You can only pass %s entity to this mapper.', Post::class)             );         }          $response = $this->postResponseFactory->create();          $response->setId($entity->getId());         $response->setPublished($entity->isPublished());         $response->setContent($entity->getContent());         $response->setSlug($entity->getSlug());         $response->setTitle($entity->getTitle());         $response->setCategoryId($entity->getCategory()?->getId());          return $response;     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p><strong>Application layer (DTORequest) &#8212; <\/strong>\u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0440\u0435\u043a\u0432\u0435\u0441\u0442 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432<\/p>\n<details class=\"spoiler\">\n<summary>DataRequestInterface &#8212; \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0435\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\DoctrineDataFeature\\Application\\DTORequest;  \/**  * Interface DataRequestInterface  * Marker for DTO request objects  * @package App\\DoctrineDataFeature\\Application\\DTORequest  **\/ interface DataRequestInterface {  } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>CategoryRequest<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\DoctrineDataFeature\\Application\\DTORequest;  use App\\DataManagerFeatureApi\\DTORequest\\CategoryDataRequestInterface;  \/**  * Class CategoryUpdate  * Request object for a category creation  * @package App\\DoctrineDataFeature\\Application\\DTORequest  **\/ class CategoryRequest implements CategoryDataRequestInterface, DataRequestInterface {     private ?int $id = null;     private ?string $title = null;     private ?string $content = null;     private ?string $slug = null;     private bool $isActive = false;      \/**      * @return int|null      *\/     public function getId(): ?int     {         return $this->id;     }      \/**      * @param int|null $id      *\/     public function setId(int $id = null): void     {         $this->id = $id;     }      \/**      * @return string|null      *\/     public function getTitle(): ?string     {         return $this->title;     }      \/**      * @param string|null $title      *\/     public function setTitle(string $title = null): void     {         $this->title = $title;     }      \/**      * @return string|null      *\/     public function getContent(): ?string     {         return $this->content;     }      \/**      * @param string|null $content      *\/     public function setContent(string $content = null): void     {         $this->content = $content;     }      \/**      * @return string|null      *\/     public function getSlug(): ?string     {         return $this->slug;     }      \/**      * @param string|null $slug      *\/     public function setSlug(string $slug = null): void     {         $this->slug = $slug;     }      \/**      * @return bool      *\/     public function isActive(): bool     {         return $this->isActive;     }      \/**      * @param bool $active      *\/     public function setActive(bool $active): void     {         $this->isActive = $active;     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>PostRequest<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\DoctrineDataFeature\\Application\\DTORequest;  use App\\DataManagerFeatureApi\\DTORequest\\PostDataRequestInterface;  \/**  * Class PostRequest  * Request object for a post creation  * @package App\\DoctrineDataFeature\\Application\\DTORequest  *\/ class PostRequest implements PostDataRequestInterface, DataRequestInterface {     private ?int $id = null;     private ?string $title = null;     private ?string $content = null;     private ?string $slug = null;     private bool $isPublished = false;     private ?int $categoryId = null;      \/**      * @return int|null      *\/     public function getId(): ?int     {         return $this->id;     }      \/**      * @param int|null $id      *\/     public function setId(int $id = null): void     {         $this->id = $id;     }      \/**      * @return string|null      *\/     public function getTitle(): ?string     {         return $this->title;     }      \/**      * @param string|null $title      *\/     public function setTitle(string $title = null): void     {         $this->title = $title;     }      \/**      * @return string|null      *\/     public function getContent(): ?string     {         return $this->content;     }      \/**      * @param string|null $content      *\/     public function setContent(string $content = null): void     {         $this->content = $content;     }      \/**      * @return string      *\/     public function getSlug(): string     {         return $this->slug;     }      \/**      * @param string|null $slug      *\/     public function setSlug(string $slug = null): void     {         $this->slug = $slug;     }      \/**      * @return bool      *\/     public function isPublished(): bool     {         return $this->isPublished;     }      \/**      * @param bool $published      *\/     public function setPublished(bool $published): void     {         $this->isPublished = $published;     }      \/**      * @param int|null $id      * @return void      *\/     public function setCategoryId(int $id = null): void     {        $this->categoryId = $id;     }      \/**      * @return int|null      *\/     public function getCategoryId(): ?int     {        return $this->categoryId;     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p><strong>Application layer (DTORequestFactory) &#8212; <\/strong>\u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0444\u0430\u0431\u0440\u0438\u043a<\/p>\n<details class=\"spoiler\">\n<summary>CategoryRequestFactory<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\DoctrineDataFeature\\Application\\DTORequestFactory;  use App\\DataManagerFeatureApi\\DTORequest\\CategoryDataRequestInterface; use App\\DataManagerFeatureApi\\DTORequestFactory\\CategoryDataRequestFactoryInterface; use App\\DoctrineDataFeature\\Application\\DTORequest\\CategoryRequest;  \/**  * Class CategoryCreateFactory  * @package App\\DoctrineDataFeature\\Application\\DTORequestFactory  **\/ class CategoryRequestFactory implements CategoryDataRequestFactoryInterface {     \/**      * @return CategoryDataRequestInterface      *\/     public function create(): CategoryDataRequestInterface     {         return new CategoryRequest();     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>PostRequestFactory<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\DoctrineDataFeature\\Application\\DTORequestFactory;  use App\\DataManagerFeatureApi\\DTORequest\\PostDataRequestInterface; use App\\DataManagerFeatureApi\\DTORequestFactory\\PostDataRequestFactoryInterface; use App\\DoctrineDataFeature\\Application\\DTORequest\\PostRequest;  \/**  * Class PostRequestFactory  * @package App\\DoctrineDataFeature\\Application\\DTORequestFactory  *\/ class PostRequestFactory implements PostDataRequestFactoryInterface {     \/**      * @return PostDataRequestInterface      *\/     public function create(): PostDataRequestInterface     {         return new PostRequest();     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p><strong>Application layer (DTOResponse) &#8212; <\/strong>\u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0440\u0435\u0441\u043f\u043e\u043d\u0441 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432<\/p>\n<details class=\"spoiler\">\n<summary>DataResponseInterface &#8212; \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0435\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\DoctrineDataFeature\\Application\\DTOResponse;  \/**  * Interface DataResponseInterface  * Marker for DTO request objects  * @package App\\DoctrineDataFeature\\Application\\DTOResponse  **\/ interface DataResponseInterface {  } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>CategoryResponse<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\DoctrineDataFeature\\Application\\DTOResponse;  use App\\DataManagerFeatureApi\\DTOResponse\\CategoryDataResponseInterface;  \/**  * Class Category  * Module response object. This object will be returned for other features usage.  * @package App\\DoctrineDataFeature\\Application\\DTOResponse  **\/ class CategoryResponse implements CategoryDataResponseInterface, DataResponseInterface {     private ?int $id = null;     private ?string $title = null;     private ?string $content = null;     private ?string $slug = null;     private bool $isActive = false;      \/**      * @return int|null      *\/     public function getId(): ?int     {         return $this->id;     }      \/**      * @param int|null $id      *\/     public function setId(int $id = null): void     {         $this->id = $id;     }      \/**      * @return string|null      *\/     public function getTitle(): ?string     {         return $this->title;     }      \/**      * @param string|null $title      *\/     public function setTitle(string $title = null): void     {         $this->title = $title;     }      \/**      * @return string|null      *\/     public function getContent(): ?string     {         return $this->content;     }      \/**      * @param string|null $content      *\/     public function setContent(string $content = null): void     {         $this->content = $content;     }      \/**      * @return string      *\/     public function getSlug(): string     {         return $this->slug;     }      \/**      * @param string|null $slug      *\/     public function setSlug(string $slug = null): void     {         $this->slug = $slug;     }      \/**      * @return bool      *\/     public function isActive(): bool     {         return $this->isActive;     }      \/**      * @param bool $active      *\/     public function setActive(bool $active): void     {         $this->isActive = $active;     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>PostResponse<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\DoctrineDataFeature\\Application\\DTOResponse;  use App\\DataManagerFeatureApi\\DTOResponse\\PostDataResponseInterface; use DateTimeInterface;  \/**  * Class PostResponse  * Module response object. This object will be returned for other features usage.  * @package App\\DoctrineDataFeature\\Application\\DTOResponse  *\/ class PostResponse implements PostDataResponseInterface, DataResponseInterface {     private ?int $id = null;     private ?string $title = null;     private ?string $content = null;     private ?string $slug = null;     private bool $isPublished = false;     private ?int $categoryId = null;     private ?string $createdAt = null;     private ?string $updatedAt = null;      \/**      * @return int|null      *\/     public function getId(): ?int     {         return $this->id;     }      \/**      * @param int|null $id      *\/     public function setId(int $id = null): void     {         $this->id = $id;     }      \/**      * @return string|null      *\/     public function getTitle(): ?string     {         return $this->title;     }      \/**      * @param string|null $title      *\/     public function setTitle(string $title = null): void     {         $this->title = $title;     }      \/**      * @return string|null      *\/     public function getContent(): ?string     {         return $this->content;     }      \/**      * @param string|null $content      *\/     public function setContent(string $content = null): void     {         $this->content = $content;     }      \/**      * @return string      *\/     public function getSlug(): string     {         return $this->slug;     }      \/**      * @param string|null $slug      *\/     public function setSlug(string $slug = null): void     {         $this->slug = $slug;     }      \/**      * @return bool      *\/     public function isPublished(): bool     {         return $this->isPublished;     }      \/**      * @param bool $published      *\/     public function setPublished(bool $published): void     {         $this->isPublished = $published;     }      \/**      * @return string|null      *\/     public function getUpdatedAt(): ?string     {         return date(\"Y-m-d\", $this->updatedAt);     }      \/**      * @param string|null $updatedAt      * @return void      *\/     public function setUpdatedAt(string $updatedAt = null): void     {         $this->updatedAt = $updatedAt;     }      \/**      * @return string      *\/     public function getCreatedAt(): string     {         return date(\"Y-m-d\", $this->createdAt);     }      \/**      * @param string|null $createdAt      * @return void      *\/     public function setCreatedAt(string $createdAt = null): void     {         $this->createdAt = $createdAt;     }      \/**      * @param int|null $id      * @return void      *\/     public function setCategoryId(int $id = null): void     {         $this->categoryId = $id;     }      \/**      * @return int|null      *\/     public function getCategoryId(): ?int     {         return $this->categoryId;     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p><strong>Application layer (DTOResponseFactory) &#8212; <\/strong>\u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0444\u0430\u0431\u0440\u0438\u043a<\/p>\n<details class=\"spoiler\">\n<summary>CategoryResponseFactoryInterface &#8212; \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0432\u043d\u0443\u0442\u0440\u0438 \u0444\u0438\u0447\u0438<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\DoctrineDataFeature\\Application\\DTOResponseFactory;  use App\\DataManagerFeatureApi\\DTOResponse\\CategoryDataResponseInterface;  \/**  * Interface CategoryResponseFactoryInterface  * @package App\\DoctrineDataFeature\\Application\\DTOResponseFactory  **\/ interface CategoryResponseFactoryInterface {     \/**      * @return CategoryDataResponseInterface      *\/     public function create(): CategoryDataResponseInterface; } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>CategoryResponseFactory<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\DoctrineDataFeature\\Application\\DTOResponseFactory;  use App\\DataManagerFeatureApi\\DTOResponse\\CategoryDataResponseInterface; use App\\DoctrineDataFeature\\Application\\DTOResponse\\CategoryResponse;  \/**  * Class CategoryResponseFactory  * @package App\\DoctrineDataFeature\\Application\\DTOResponseFactory  **\/ class CategoryResponseFactory implements CategoryResponseFactoryInterface {     \/**      * @return CategoryDataResponseInterface      *\/     public function create(): CategoryDataResponseInterface     {         return new CategoryResponse();     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>PostResponseFactoryInterface &#8212; \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0432\u043d\u0443\u0442\u0440\u0438 \u0444\u0438\u0447\u0438<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\DoctrineDataFeature\\Application\\DTOResponseFactory;  use App\\DataManagerFeatureApi\\DTOResponse\\PostDataResponseInterface;  \/**  * Interface PostResponseFactoryInterface  * @package App\\DoctrineDataFeature\\Application\\DTOResponseFactory  *\/ interface PostResponseFactoryInterface {     \/**      * @return PostDataResponseInterface      *\/     public function create(): PostDataResponseInterface; } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>PostResponseFactory<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\DoctrineDataFeature\\Application\\DTOResponseFactory;  use App\\DataManagerFeatureApi\\DTOResponse\\PostDataResponseInterface; use App\\DoctrineDataFeature\\Application\\DTOResponse\\PostResponse;  \/**  * Class PostResponseFactory  * @package App\\DoctrineDataFeature\\Application\\DTOResponseFactory  *\/ class PostResponseFactory implements PostResponseFactoryInterface {     \/**      * @return PostDataResponseInterface      *\/     public function create(): PostDataResponseInterface     {         return new PostResponse();     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0422.\u043a. \u0441\u0438\u043c\u0444\u043e\u043d\u0438 \u0438\u043c\u0435\u0435\u0442 \u0441\u0432\u043e\u0438 \u043f\u0440\u0438\u0432\u044f\u0437\u043a\u0438 \u043a \u043f\u0430\u043f\u043a\u0430\u043c, \u0430 \u043c\u044b \u0443\u0436\u0435 \u0441\u043e\u0437\u0434\u0430\u043b\u0438 DoctrineEntity \u0432 \u043d\u0435\u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u043c \u0444\u043e\u043b\u0434\u0435\u0440\u0435, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0437\u0434\u0435\u0441\u044c <strong>config\/packages\/doctrine.yaml<\/strong> \u0432 &#171;orm&#187; \u043f\u0440\u043e\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:<\/p>\n<pre><code>    orm:         auto_generate_proxy_classes: true         enable_lazy_ghost_objects: true         naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware         auto_mapping: true         mappings:             doctrine_data_manager_feature:                 is_bundle: false                 type: attribute                 dir: '%kernel.project_dir%\/src\/DoctrineDataFeature\/Domain\/Entity'                 prefix: 'App\\DoctrineDataFeature\\Domain\\Entity\\'                 alias: doctrine_data_manager_feature<\/code><\/pre>\n<p>\u0418 \u0442\u0430\u043a, \u0443 \u043d\u0430\u0441 \u0443\u0436\u0435 \u0435\u0441\u0442\u044c \u043c\u043e\u0434\u0443\u043b\u044c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0443\u043c\u0435\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438. \u041d\u0430\u0432\u0435\u0440\u043d\u044f\u043a\u0430, \u0432\u044b \u0437\u0430\u0434\u0430\u0434\u0438\u0442\u0435 \u0432\u043e\u043f\u0440\u043e\u0441 &#171;<em>\u0410 \u0437\u0430\u0447\u0435\u043c \u043d\u0430\u043c \u0442\u043e\u0433\u0434\u0430 \u043d\u0443\u0436\u043d\u044b \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u0444\u0438\u0447\u0438 \u0434\u043b\u044f \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0439 \u0438 \u043f\u043e\u0441\u0442\u043e\u0432, \u043a\u043e\u0433\u0434\u0430 \u043c\u044b \u0438 \u0442\u0430\u043a \u0443\u0436\u0435 \u0441\u043c\u043e\u0436\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u0442\u044c\/\u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c\/\u0443\u0434\u0430\u043b\u0438\u0442\u044c \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u044e \u0438 \u043f\u043e\u0441\u0442<\/em>?&#187;. <\/p>\n<p>\u041e\u0442\u0432\u0435\u0442 \u043f\u0440\u043e\u0441\u0442 &#8212; DoctirneManagerFeature (\u0430 \u0442\u0430\u043a \u0436\u0435 \u0432\u0441\u0435, \u0447\u0442\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442 DataManagerFeatureApi) \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0438\u0437 \u0441\u0435\u0431\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u0434\u0430\u043d\u043d\u044b\u0445, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0443\u043c\u0435\u0435\u0442 \u043f\u0440\u043e\u0441\u0442\u043e \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u0438 \u0434\u043e\u0441\u0442\u0430\u0432\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435. \u0417\u0434\u0435\u0441\u044c \u043d\u0435\u0442 \u0431\u0438\u0437\u043d\u0435\u0441 \u043b\u043e\u0433\u0438\u043a\u0438, \u043d\u0435\u0442 \u043f\u0435\u0440\u0432\u0438\u0447\u043d\u043e\u0439 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 \u0438 \u0442\u0434. \u0417\u0430\u0434\u0430\u0447\u0430 \u044d\u0442\u043e\u0433\u043e \u043c\u043e\u0434\u0443\u043b\u044f &#8212; \u044d\u0442\u043e \u0440\u0430\u0431\u043e\u0442\u0430 \u0441 \u0434\u0430\u0442\u0430 \u0441\u0442\u043e\u0440\u0430\u0434\u0436. <em>\u041f\u043e\u0447\u0435\u043c\u0443 \u043d\u0435\u043b\u044c\u0437\u044f \u0441\u044e\u0434\u0430 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0431\u0438\u0437\u043d\u0435\u0441 \u043b\u043e\u0433\u0438\u043a\u0443?<\/em> \u041f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e, \u0432\u043e-\u043f\u0435\u0440\u0432\u044b\u0445, \u043c\u044b \u043f\u0440\u0438\u0432\u044f\u0436\u0435\u043c\u0441\u044f \u043a \u0434\u043e\u043a\u0442\u0440\u0438\u043d\u0435, \u0432\u043e-\u0432\u0442\u043e\u0440\u044b\u0445, \u0435\u0441\u043b\u0438 \u043c\u044b \u0437\u0430\u0445\u043e\u0442\u0438\u043c \u043f\u043e\u043c\u0435\u043d\u044f\u0442\u044c \u0434\u0430\u0442\u0430 \u0441\u0442\u043e\u0440\u0430\u0434\u0436, \u0442\u043e\u0433\u0434\u0430 \u043d\u0430\u043c \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u0434\u0443\u0431\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0431\u0438\u0437\u043d\u0435\u0441 \u043b\u043e\u0433\u0438\u043a\u0443 \u0432 \u0444\u0438\u0447\u0443, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0441 \u0434\u0440\u0443\u0433\u0438\u043c \u0434\u0430\u0442\u0430 \u0441\u0442\u043e\u0440\u0430\u0434\u0436. \u041f\u0440\u0438 \u044d\u0442\u043e\u043c, \u0435\u0441\u043b\u0438 \u043a\u0430\u043a\u043e\u0439-\u0442\u043e \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0432 \u0431\u0438\u0437\u043d\u0435\u0441 \u043b\u043e\u0433\u0438\u043a\u0435 \u043f\u043e\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f, \u0442\u043e \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u0438\u0437\u043c\u0435\u043d\u044f\u0442\u044c \u043a\u043e\u0434 \u0432\u043e \u0432\u0441\u0435\u0445 \u0444\u0438\u0447\u0430\u0445. \u041d\u0430\u0448 \u043f\u043e\u0434\u0445\u043e\u0434 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0431\u044b\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u0438\u0437\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u043c \u0438 \u0433\u0438\u0431\u043a\u0438\u043c.<\/p>\n<h2>CategoryFeatureApi \u0438 CategoryFeature<\/h2>\n<p><a class=\"anchor\" name=\"category_feature\" id=\"category_feature\"><\/a><\/p>\n<p>Api \u0434\u043b\u044f \u043c\u043e\u0434\u0443\u043b\u0435\u0439 \u0431\u0443\u0434\u0443\u0442 \u0441\u0445\u043e\u0436\u0438\u043c\u0438 \u043c\u0435\u0436\u0434\u0443 \u0441\u043e\u0431\u043e\u0439 \u043f\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435 \u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044e. \u0412\u044b\u0448\u0435 \u044f \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u043b\u0430 \u0431\u043e\u043b\u0435\u0435 \u0434\u0435\u0442\u0430\u043b\u044c\u043d\u043e  DataManagerFeatureApi, \u0437\u0434\u0435\u0441\u044c \u044f \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0440\u0438\u0432\u0435\u0434\u0443 \u043a\u043e\u0434 \u0434\u043b\u044f <strong>CategoryFeatureApi<\/strong> \u0441 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u043c\u0438 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u043c\u0438<\/p>\n<details class=\"spoiler\">\n<summary>CategoryCreateRequestInterface &#8212; \u0440\u0435\u043a\u0432\u0435\u0441\u0442 \u043e\u0431\u044a\u0435\u043a\u0442 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0438<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\CategoryFeatureApi\\DTORequest;  \/**  * @api  * Interface CategoryCreateRequestInterface  * @package App\\CategoryFeatureApi\\DTORequest  *  * Request object for a category creation  *  * WARNING! API DOESN'T know anything about realization!  * This interfaces provides public access for other features to a feature realization.  *\/ interface CategoryCreateRequestInterface {     \/**      * @return string|null      *\/     public function getTitle(): ?string;      \/**      * @param string|null $title      *\/     public function setTitle(string $title = null): void;      \/**      * @return string|null      *\/     public function getContent(): ?string;      \/**      * @param string|null $content      *\/     public function setContent(string $content = null): void;      \/**      * @return string|null      *\/     public function getSlug(): ?string;      \/**      * @param string|null $slug      *\/     public function setSlug(string $slug = null): void;      \/**      * @return bool      *\/     public function isActive(): bool;      \/**      * @param bool $active      *\/     public function setActive(bool $active): void; } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>CategoryUpdateRequestInterface &#8212; \u0440\u0435\u043a\u0432\u0435\u0441\u0442 \u043e\u0431\u044a\u0435\u043a\u0442 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0434\u043b\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0438<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\CategoryFeatureApi\\DTORequest;  \/**  * @api  * Interface CategoryUpdateRequestInterface  * @package App\\CategoryFeatureApi\\DTORequest  *  * Request object for a category updates  *  * WARNING! API DOESN'T know anything about realization!  * This interfaces provides public access for other features to a feature realization.  *\/ interface CategoryUpdateRequestInterface {     \/**      * @return int|null      *\/     public function getId(): ?int;      \/**      * @param int|null $id      *\/     public function setId(int $id = null): void;      \/**      * @return string|null      *\/     public function getTitle(): ?string;      \/**      * @param string|null $title      *\/     public function setTitle(string $title = null): void;      \/**      * @return string|null      *\/     public function getContent(): ?string;      \/**      * @param string|null $content      *\/     public function setContent(string $content = null): void;      \/**      * @return string|null      *\/     public function getSlug(): ?string;      \/**      * @param string|null $slug      *\/     public function setSlug(string $slug = null): void;      \/**      * @return bool      *\/     public function isActive(): bool;      \/**      * @param bool $active      *\/     public function setActive(bool $active): void; } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>CategoryCreateDTOFactoryInterface<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\CategoryFeatureApi\\DTORequestFactory;  use App\\CategoryFeatureApi\\DTORequest\\CategoryCreateRequestInterface;  \/**  * @api  * Interface CategoryCreateDTOFactoryInterface  * @package App\\CategoryFeatureApi\\DTORequestFactory  *  * WARNING! API DOESN'T know anything about realization!  * This interfaces provides public access for other features to a feature realization.  *\/ interface CategoryCreateDTOFactoryInterface {     \/**      * @return CategoryCreateRequestInterface      *\/     public function create(): CategoryCreateRequestInterface; } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>CategoryUpdateDTOFactoryInterface<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\CategoryFeatureApi\\DTORequestFactory;  use App\\CategoryFeatureApi\\DTORequest\\CategoryUpdateRequestInterface;  \/**  * @api  * Interface CategoryUpdateDTOFactoryInterface  * @package App\\CategoryFeatureApi\\DTORequestFactory  *  * WARNING! API DOESN'T know anything about realization!  * This interfaces provides public access for other features to a feature realization.  *\/ interface CategoryUpdateDTOFactoryInterface {     \/**      * @return CategoryUpdateRequestInterface      *\/     public function create(): CategoryUpdateRequestInterface; } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>CategoryDTOInterface &#8212; \u0440\u0435\u0441\u043f\u043e\u043d\u0441 \u043e\u0431\u044a\u0435\u043a\u0442 \u0431\u0443\u0434\u0435\u0442 \u0432\u0441\u0435\u0433\u0434\u0430 \u043e\u0434\u0438\u043d, \u043d\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e \u043e\u0442 \u0442\u0438\u043f\u0430 \u0440\u0435\u043a\u0432\u0435\u0441\u0442\u0430<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\CategoryFeatureApi\\DTOResponse;  \/**  * @api  * Interface CategoryDTOInterface  * @package App\\CategoryFeatureApi\\DTOResponse  *  * Module response object. This object will be returned for other features usage.  *  * WARNING! API DOESN'T know anything about realization!  * This interfaces provides public access for other features to a feature realization.  **\/ interface CategoryDTOInterface {     \/**      * @return int|null      *\/     public function getId(): ?int;      \/**      * @param int|null $id      *\/     public function setId(int $id = null): void;      \/**      * @return string|null      *\/     public function getTitle(): ?string;      \/**      * @param string|null $title      *\/     public function setTitle(string $title = null): void;      \/**      * @return string|null      *\/     public function getContent(): ?string;      \/**      * @param string|null $content      *\/     public function setContent(string $content = null): void;      \/**      * @return string      *\/     public function getSlug(): string;      \/**      * @param string|null $slug      *\/     public function setSlug(string $slug = null): void;      \/**      * @return bool      *\/     public function isActive(): bool;      \/**      * @param bool $active      *\/     public function setActive(bool $active): void; } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>CategoryServiceInterface &#8212; \u043d\u0430\u0431\u043e\u0440 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u0445 \u043c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0446\u0438\u0439 \u0441 \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0435\u0439<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\CategoryFeatureApi\\Service;  use App\\CategoryFeatureApi\\DTORequest\\CategoryUpdateRequestInterface as UpdateDTORequest; use App\\CategoryFeatureApi\\DTORequest\\CategoryCreateRequestInterface as CreateDTORequest; use App\\CategoryFeatureApi\\DTOResponse\\CategoryDTOInterface as ResponseDTO;  \/**  * @api  * Interface CategoryServiceInterface  * @package App\\CategoryFeatureApi\\Service  *  * Api service for categories management  *  * WARNING! API DOESN'T know anything about realization!  * This interfaces provides public access for other features to a feature realization.  *\/ interface CategoryServiceInterface {     \/**      * @param array|null $criteria      * @return array      *\/     public function getList(array $criteria = null): array;      \/**      * @param int $categoryId      * @return ResponseDTO|null      *\/     public function getById(int $categoryId): ?ResponseDTO;      \/**      * @param string $slug      * @return ResponseDTO|null      *\/     public function getBySlug(string $slug): ?ResponseDTO;      \/**      * @return ResponseDTO      *\/     public function initNewCategory(): ResponseDTO;      \/**      * @param CreateDTORequest $dtoRequest      * @return ResponseDTO      *\/     public function create(CreateDTORequest $dtoRequest): ResponseDTO;      \/**      * @param UpdateDTORequest $dtoRequest      * @return ResponseDTO      *\/     public function update(UpdateDTORequest $dtoRequest): ResponseDTO;      \/**      * @param int $id      * @return void      *\/     public function deleteById(int $id): void; } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0412 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0442\u0430\u043a\u0436\u0435, \u043a\u0430\u043a \u0438 \u0434\u043b\u044f \u0434\u0430\u0442\u0430 \u0444\u0438\u0447\u0438<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/a5a\/91b\/dc1\/a5a91bdc163864487493e84fa5e2cf28.png\" width=\"404\" height=\"275\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/a5a\/91b\/dc1\/a5a91bdc163864487493e84fa5e2cf28.png\"\/><figcaption><\/figcaption><\/figure>\n<h3>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f CategoryFeature<\/h3>\n<p>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0431\u0443\u0434\u0435\u0442 \u0441\u0445\u043e\u0436\u0430, \u043d\u043e \u0437\u0434\u0435\u0441\u044c \u0443\u0436\u0435 \u0431\u0443\u0434\u0443\u0442 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u044b \u043d\u043e\u0432\u044b\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u044b. \u041e\u0431\u043e \u0432\u0441\u0435\u043c \u043d\u0438\u0436\u0435.<\/p>\n<p>\u0422\u0430\u043a \u0436\u0435 \u043d\u0430\u0447\u043d\u0435\u043c \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 \u0434\u043e\u043c\u0435\u043d\u043d\u043e\u0433\u043e \u0441\u043b\u043e\u044f. \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u043c\u044b \u0432\u044b\u0434\u0435\u043b\u044f\u0435\u043c \u0431\u0438\u0437\u043d\u0435\u0441 \u0441\u043b\u043e\u0439, \u0430 \u043f\u043e\u0442\u043e\u043c \u0443\u0436\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0441 \u043d\u0438\u043c. <\/p>\n<hr\/>\n<h3>Domain layer<\/h3>\n<p><strong>CategoryFeature (Domain layer)<\/strong><\/p>\n<p>\u0412 \u0434\u043e\u043c\u0435\u043d\u043d\u043e\u043c \u0441\u043b\u043e\u0435 \u0443 \u043d\u0430\u0441 \u043f\u043e\u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0418\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u043e\u0440\u044b (Interactor) \u0438 Value object. \u041f\u043e \u043f\u043e\u0432\u043e\u0434\u0443 \u0438\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u043e\u0440\u043e\u0432 \u0431\u044b\u043b\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043e \u0432\u044b\u0448\u0435, \u043e\u043d\u0438 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u044e\u0442 \u0432 \u0433\u0440\u0443\u043f\u043f\u0443 usecase (\u0442.\u0435. \u043d\u0430\u0431\u043e\u0440 \u0431\u0438\u0437\u043d\u0435\u0441 \u043b\u043e\u0433\u0438\u043a\u0438). \u041d\u0430\u0448\u0438 DomainEntity \u0431\u0443\u0434\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c immutable value objects. \u0414\u0435\u043b\u0430\u0435\u0442\u0441\u044f \u044d\u0442\u043e \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0434\u043e\u043c\u0435\u043d\u043d\u0443\u044e \u043c\u043e\u0434\u0435\u043b\u044c \u043d\u0438\u043a\u0442\u043e \u043d\u0435 \u0441\u043c\u043e\u0433 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c. \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043e ValueObject \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u0432 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0435. \u0410 \u043c\u044b \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0435\u043c:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/9f4\/e0c\/a8a\/9f4e0ca8a11c6e446c30c1f6d244bc45.png\" width=\"1083\" height=\"395\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/9f4\/e0c\/a8a\/9f4e0ca8a11c6e446c30c1f6d244bc45.png\"\/><figcaption><\/figcaption><\/figure>\n<p><strong>Domain layer (Entity)<\/strong><\/p>\n<details class=\"spoiler\">\n<summary>Category &#8212; domain entity. \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 ValueObjects<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\CategoryFeature\\Domain\\Entity;  use App\\CategoryFeature\\Domain\\ValueObject\\ContentValue; use App\\CategoryFeature\\Domain\\ValueObject\\IdValue; use App\\CategoryFeature\\Domain\\ValueObject\\SlugValue; use App\\CategoryFeature\\Domain\\ValueObject\\ActiveValue; use App\\CategoryFeature\\Domain\\ValueObject\\TitleValue;  \/**  * Class Category  * @package App\\CategoryFeature\\Domain\\Entity  *  * Domain Entity doesn't connect to any DB or other storages.  * Represents an element of business logic.  * Domain entities must not be revealed outside  *  * Use immutable value objects here  *\/ class Category {     private IdValue $id;     private TitleValue $title;     private ContentValue $content;     private SlugValue $slug;     private ActiveValue $isActive;      \/**      * @return IdValue      *\/     public function getId(): IdValue     {         return $this->id;     }      \/**      * @param IdValue $id      *\/     public function setId(IdValue $id): void     {         $this->id = $id;     }      \/**      * @return TitleValue      *\/     public function getTitle(): TitleValue     {         return $this->title;     }      \/**      * @param TitleValue $title      *\/     public function setTitle(TitleValue $title): void     {         $this->title = $title;     }      \/**      * @return ContentValue      *\/     public function getContent(): ContentValue     {         return $this->content;     }      \/**      * @param ContentValue $content      *\/     public function setContent(ContentValue $content): void     {         $this->content = $content;     }      \/**      * @return SlugValue      *\/     public function getSlug(): SlugValue     {         return $this->slug;     }      \/**      * @param SlugValue $slug      *\/     public function setSlug(SlugValue $slug): void     {         $this->slug = $slug;     }      \/**      * @return ActiveValue      *\/     public function isActive(): ActiveValue     {         return $this->isActive;     }      \/**      * @param ActiveValue $active      *\/     public function setActive(ActiveValue $active): void     {         $this->isActive = $active;     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p><strong>Domain layer (Factory)<\/strong><\/p>\n<details class=\"spoiler\">\n<summary>CategoryFactory<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\CategoryFeature\\Domain\\Factory;  use App\\CategoryFeature\\Domain\\Entity\\Category; use App\\CategoryFeature\\Domain\\ValueObject\\ContentValue; use App\\CategoryFeature\\Domain\\ValueObject\\IdValue; use App\\CategoryFeature\\Domain\\ValueObject\\SlugValue; use App\\CategoryFeature\\Domain\\ValueObject\\ActiveValue; use App\\CategoryFeature\\Domain\\ValueObject\\TitleValue;  \/**  * Class CategoryFactory  * @package App\\CategoryFeature\\Domain\\Factory  *\/ class CategoryFactory {     \/**      * @param int|null $id      * @param string|null $title      * @param string|null $content      * @param string|null $slug      * @param bool $isActive      * @return Category      *\/     public function create(         int    $id = null,         string $title = null,         string $content = null,         string $slug = null,         bool   $isActive = false,     ): Category     {         $category = new Category();          $idValue = new IdValue($id);         $category->setId($idValue);          $titleValue = new TitleValue($title);         $category->setTitle($titleValue);          $contentValue = new ContentValue($content);         $category->setContent($contentValue);          $slugValue = new SlugValue($slug);         $category->setSlug($slugValue);          $statusValue = new ActiveValue($isActive);         $category->setActive($statusValue);          return $category;     } } <\/code><\/pre>\n<\/p>\n<\/p>\n<\/div>\n<\/details>\n<p><strong>Domain layer (Repository)<\/strong><\/p>\n<details class=\"spoiler\">\n<summary>CategoryRepositoryInterface &#8212; \u043d\u0435 \u0437\u0430\u0431\u044b\u0432\u0430\u0435\u043c, \u0447\u0442\u043e \u0432 \u0434\u043e\u043c\u0435\u043d\u0435 \u043d\u0435\u0442 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f, \u0442\u043e\u043b\u044c\u043a\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\CategoryFeature\\Domain\\Repository;  use App\\CategoryFeature\\Domain\\Entity\\Category;  \/**  * Interface CategoryRepositoryInterface  * @package App\\CategoryFeature\\Domain\\Repository  *  * Domain layer NEVER implements repository. Domain doesn't know anything about data storages.  * Domain uses behavior description, repository must be implemented in Infrastructure layer according to a source  * (eg. DB, Session and so on)  *\/ interface CategoryRepositoryInterface {     \/**      * @param Category $category      * @return Category      *\/     public function save(Category $category): Category;      \/**      * @param int $id      *\/     public function deleteById(int $id): void;      \/**      * @param array|null $criteria      * @return array      *\/     public function getList(array $criteria = null): array;      \/**      * @param int $id      * @return Category|null      *\/     public function getById(int $id): ?Category;      \/**      * @param string $slug      * @return Category|null      *\/     public function getBySlug(string $slug): ?Category; } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p><strong>Domain layer (Interactor) &#8212; <\/strong>\u044f \u0432\u044b\u0434\u0435\u043b\u0438\u043b\u0430 \u0442\u0440\u0438 \u0438\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u043e\u0440\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u044e\u0442 \u0432 \u0441\u0435\u0431\u0435 \u043e\u0431\u0449\u0438\u0435 \u0437\u0430\u0434\u0430\u0447\u0438. \u0418\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u043e\u0440 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f, \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f (\u043a\u0443\u0434\u0430 \u0432\u0445\u043e\u0434\u0438\u0442 update and create \u043c\u0435\u0442\u043e\u0434\u044b), \u0438\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u043e\u0440 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 (loadById \u0438 \u0442\u0434). \u0422.\u043a. \u0431\u0438\u0437\u043d\u0435\u0441 \u043b\u043e\u0433\u0438\u043a\u0430 \u043d\u0435 \u0434\u043e\u043b\u0436\u043d\u0430 \u0438\u0437\u043c\u0435\u043d\u044f\u0442\u044c\u0441\u044f \u0438\u0437\u0432\u043d\u0435, \u043d\u0435 \u0437\u0430\u0431\u044b\u0432\u0430\u0435\u043c \u0438\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u043e\u0440\u044b \u043e\u0431\u044a\u044f\u0432\u043b\u044f\u0442\u044c \u043a\u0430\u043a final<\/p>\n<details class=\"spoiler\">\n<summary>CategoryDeleteInteractor<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\CategoryFeature\\Domain\\Interactor;  use App\\CategoryFeature\\Domain\\Entity\\Category; use App\\CategoryFeature\\Domain\\Repository\\CategoryRepositoryInterface; use DomainException;  \/**  * Class CategoryDeleteInteractor  * @package App\\CategoryFeature\\Domain\\Interactor  *  * Interactor represents a union of use cases. 1 use case = 1 business logic action.  * e.g. deleteById() method represents delete category by id use case.  * Interactor holds use cases for the sake of decreasing complexity of the code and decreasing dependencies for classes  * which will need several use cases.  *  * WARNING! Interactors must not be changed or inherited.  * Business logic can't be changed by 3-d party modules and layers  *\/ final class CategoryDeleteInteractor {     private CategoryRepositoryInterface $categoryRepository;      \/**      * @param CategoryRepositoryInterface $categoryRepository      *\/     public function __construct(CategoryRepositoryInterface $categoryRepository)     {         $this->categoryRepository = $categoryRepository;     }      \/**      * @param int $id      * @return void      * @throws DomainException      *\/     public function deleteById(int $id): void     {         $category = $this->categoryRepository->getById($id);          if (null == $category) {             throw new DomainException(sprintf(\"Category with id %s does not exist\", $id));         }          $this->categoryRepository->deleteById($id);     }      \/**      * @param Category $category      * @return void      * @throws DomainException      *\/     public function delete(Category $category): void     {         $categoryId = $category->getId()->getValue();          if (null == $categoryId) {             throw new DomainException(\"Can't remove category without Id\");         }          $this->categoryRepository->deleteById($categoryId);     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>CategoryLoadInteractor<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\CategoryFeature\\Domain\\Interactor;  use App\\CategoryFeature\\Domain\\Entity\\Category; use App\\CategoryFeature\\Domain\\Factory\\CategoryFactory; use App\\CategoryFeature\\Domain\\Repository\\CategoryRepositoryInterface;  \/**  * Class CategoryLoadInteractor  * @package App\\CategoryFeature\\Domain\\Interactor  *  * Interactor represents a union of use cases. 1 use case = 1 business logic action.  * e.g. loadById() method represents load category by id use case.  * Interactor holds use cases for the sake of decreasing complexity of the code and decreasing dependencies for classes  * which will need several use cases.  *  * WARNING! Interactors must not be changed or inherited.  * Business logic can't be changed by 3-d party modules and layers  *\/ final class CategoryLoadInteractor {     private CategoryRepositoryInterface $categoryRepository;     private CategoryFactory $categoryFactory;      \/**      * @param CategoryRepositoryInterface $categoryRepository      * @param CategoryFactory $categoryFactory      *\/     public function __construct(         CategoryRepositoryInterface $categoryRepository,         CategoryFactory $categoryFactory     ) {         $this->categoryRepository = $categoryRepository;         $this->categoryFactory = $categoryFactory;     }      \/**      * @param array|null $criteria      * @return array      *\/     public function loadAll(array $criteria = null): array     {         return $this->categoryRepository->getList($criteria);     }      \/**      * @param int $id      * @return Category|null      *\/     public function loadById(int $id): ?Category     {         return $this->categoryRepository->getById($id);     }      \/**      * @return Category      *\/     public function loadEmptyCategory(): Category     {         return $this->categoryFactory->create();     }      \/**      * @param string $slug      * @return Category|null      *\/     public function loadBySlug(string $slug): ?Category     {         return $this->categoryRepository->getBySlug($slug);     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>CategorySaveInteractor<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\CategoryFeature\\Domain\\Interactor;  use App\\CategoryFeature\\Domain\\Entity\\Category; use App\\CategoryFeature\\Domain\\Repository\\CategoryRepositoryInterface; use DomainException;  \/**  * Class CategorySaveInteractor  * @package App\\CategoryFeature\\Domain\\Interactor  *  * Interactor represents a union of use cases. 1 use case = 1 business logic action.  * e.g. update() method represents update category use case.  * Interactor holds use cases for the sake of decreasing complexity of the code and decreasing dependencies for classes  * which will need several use cases.  *  * WARNING! Interactors must not be changed or inherited.  * Business logic can't be changed by 3-d party modules and layers  *\/ final class CategorySaveInteractor {     private CategoryRepositoryInterface $categoryRepository;      \/**      * @param CategoryRepositoryInterface $categoryRepository      *\/     public function __construct(CategoryRepositoryInterface $categoryRepository)     {         $this->categoryRepository = $categoryRepository;     }      \/**      * @param Category $category      * @return Category      *\/     public function update(Category $category): Category     {         if (!$category->getSlug()->getValue()) {             throw new DomainException(\"Category must have a slug\");         }          $categoryId = $category->getId()->getValue();         $existedCategory = $this->categoryRepository->getById($categoryId);          if (null == $existedCategory) {             throw new DomainException(sprintf(\"Category with id %s does not exist\", $categoryId));         }          return $this->categoryRepository->save($category);     }      \/**      * @param Category $category      * @return Category      *\/     public function create(Category $category): Category     {         $slug = $category->getSlug()->getValue();          if (!$slug) {             throw new DomainException(\"Category must have a slug\");         }          $existedCategory = $this->categoryRepository->getBySlug($slug);          if (null != $existedCategory) {             throw new DomainException(sprintf(\"Category slug '%s' already exists\", $slug));         }          return $this->categoryRepository->save($category);     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p><strong>Domain layer (ValueObject) &#8212; <\/strong>\u043e \u043d\u0438\u0445 \u043f\u0438\u0441\u0430\u043b\u0430 \u0432\u044b\u0448\u0435, \u0437\u0434\u0435\u0441\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u043e\u0434<\/p>\n<details class=\"spoiler\">\n<summary>ValueObjectInterface<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\CategoryFeature\\Domain\\ValueObject;  \/**  * Interface ValueObjectInterface  * @package App\\CategoryFeature\\Domain\\ValueObject  *\/ interface ValueObjectInterface {     \/**      * @return mixed      *\/     public function getValue();      \/**      * @return string      *\/     public function __toString(): string; } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>ActiveValue<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\CategoryFeature\\Domain\\ValueObject;  \/**  * Class StatusValue  * Warning: data value object must be immutable  *  * @package App\\CategoryFeature\\Domain\\ValueObject  *\/ class ActiveValue implements ValueObjectInterface {     private bool $status;      \/**      * @param bool $status      *\/     public function __construct(bool $status)     {         $this->status = $status;     }      \/**      * @return bool      *\/     public function getValue(): bool     {         return $this->status;     }      \/**      * @return string      *\/     public function __toString(): string     {         return (string)$this->status;     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>ContentValue<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\CategoryFeature\\Domain\\ValueObject;  \/**  * Class ContentValue  * Warning: data value object must be immutable  *  * @package App\\CategoryFeature\\Domain\\ValueObject  *\/ class ContentValue implements ValueObjectInterface {     private ?string $content;      \/**      * @param string|null $content      *\/     public function __construct(string $content = null)     {         $this->content = $content;     }      \/**      * @return string|null      *\/     public function getValue(): ?string     {         return $this->content;     }      \/**      * @return string      *\/     public function __toString(): string     {         return $this->content;     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>IdValue<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\CategoryFeature\\Domain\\ValueObject;  \/**  * Class IdValue  * Warning: data value object must be immutable  *  * @package App\\CategoryFeature\\Domain\\ValueObject  *\/ class IdValue implements ValueObjectInterface {     private ?int $id;      \/**      * @param int|null $id      *\/     public function __construct(int $id = null)     {         $this->id = $id;     }      \/**      * @return int|null      *\/     public function getValue(): ?int     {         return $this->id;     }      \/**      * @return string      *\/     public function __toString(): string     {         return (string)$this->id;     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>SlugValue<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\CategoryFeature\\Domain\\ValueObject;  \/**  * Class SlugValue  * Warning: data value object must be immutable  *  * @package App\\CategoryFeature\\Domain\\ValueObject  *\/ class SlugValue implements ValueObjectInterface {     private ?string $slug;      \/**      * @param string|null $slug      *\/     public function __construct(string $slug = null)     {         $this->slug = $slug;     }      \/**      * @return string|null      *\/     public function getValue(): ?string     {         return $this->slug;     }      \/**      * @return string      *\/     public function __toString(): string     {         return $this->slug;     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>TitleValue<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\CategoryFeature\\Domain\\ValueObject;  \/**  * Class TitleValue  * Warning: data value object must be immutable  *  * @package App\\CategoryFeature\\Domain\\ValueObject  *\/ class TitleValue implements ValueObjectInterface {     private ?string $title;      \/**      * @param string|null $title      *\/     public function __construct(string $title = null)     {         $this->title = $title;     }      \/**      * @return string|null      *\/     public function getValue(): ?string     {         return $this->title;     }      \/**      * @return string      *\/     public function __toString(): string     {         return $this->title;     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<hr\/>\n<h3>Infrastructure layer<\/h3>\n<p><strong>CategoryFeature (Infrastructure layer)<\/strong><\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0431\u0443\u0434\u0435\u043c \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043d\u0430\u0448\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0432 \u0434\u0430\u0442\u0430 \u0441\u0442\u043e\u0440\u0430\u0434\u0436. \u0421\u0445\u0435\u043c\u0430 \u0442\u0430\u043a\u0430\u044f &#8212; \u0434\u043e\u043c\u0435\u043d\u043d\u0430\u044f \u043c\u043e\u0434\u0435\u043b\u044c \u043c\u0430\u043f\u0438\u0442\u0441\u044f \u0432 \u0440\u0435\u043a\u0432\u0435\u0441\u0442 \u043e\u0431\u044a\u0435\u043a\u0442 DataManagerFeatureAPI. \u0414\u0430\u043b\u0435\u0435 \u043e\u0431\u044a\u0435\u043a\u0442 \u043f\u043e\u0441\u044b\u043b\u0430\u0435\u0442\u0441\u044f \u0432 \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u0443\u044e \u0444\u0438\u0447\u0443 (\u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 DoctrineDataFeature), \u044d\u0442\u043e\u0442 \u043e\u0431\u044a\u0435\u043a\u0442 \u0440\u0435\u043a\u0432\u0435\u0441\u0442\u0430 \u043c\u0430\u043f\u0438\u0442\u0441\u044f \u0432 \u0434\u043e\u043c\u0435\u043d\u043d\u0443\u044e \u043c\u043e\u0434\u0435\u043b\u044c Category, \u0433\u0434\u0435 \u0434\u0430\u043b\u0435\u0435 \u0447\u0435\u0440\u0435\u0437 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435\/\u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u0430, \u043f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e DoctrineDataFeature \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0440\u0435\u0441\u043f\u043e\u043d\u0441 \u043e\u0431\u044a\u0435\u043a\u0442, \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0443\u043a\u0442\u0443\u0440\u043d\u044b\u0439 \u0441\u043b\u043e\u0439 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u044d\u0442\u043e\u0442 \u0440\u0435\u0441\u043f\u043e\u043d\u0441 \u0438 \u043c\u0430\u043f\u0438\u0442 \u0435\u0433\u043e \u043e\u0431\u0440\u0430\u0442\u043d\u043e \u0432 \u0434\u043e\u043c\u0435\u043d.<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/d47\/df3\/491\/d47df3491505946c85dc69d073f1056d.png\" width=\"379\" height=\"182\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/d47\/df3\/491\/d47df3491505946c85dc69d073f1056d.png\"\/><figcaption><\/figcaption><\/figure>\n<p><strong>Infrastructure layer (DataMapper) &#8212; <\/strong>\u0437\u0434\u0435\u0441\u044c \u043c\u0430\u043f\u0438\u043c \u043e\u0431\u044a\u0435\u043a\u0442 \u0432 \u0434\u043e\u043c\u0435\u043d\u043d\u0443\u044e \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044c, \u043b\u0438\u0431\u043e \u0436\u0435 \u0432 \u0440\u0435\u0441\u043f\u043e\u043d\u0441 \u043e\u0431\u044a\u0435\u043a\u0442 \u0434\u043b\u044f \u0414\u0430\u0442\u0430\u0421\u0442\u043e\u0440\u0430\u0434\u0436.<\/p>\n<details class=\"spoiler\">\n<summary>CategoryDomainMapperInterface &#8212; \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0435\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\CategoryFeature\\Infrastructure\\DataMapper;  use App\\CategoryFeature\\Domain\\Entity\\Category; use App\\DataManagerFeatureApi\\DTOResponse\\CategoryDataResponseInterface;  \/**  * Interface CategoryDomainMapperInterface  * Map data response object to a domain object  * @package App\\CategoryFeature\\Infrastructure\\DataMapper  **\/ interface CategoryDomainMapperInterface {     \/**      * @param CategoryDataResponseInterface $dataResponse      * @return Category      *\/     public function map(CategoryDataResponseInterface $dataResponse): Category; } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>CategoryDomainMapper<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\CategoryFeature\\Infrastructure\\DataMapper;  use App\\CategoryFeature\\Domain\\Entity\\Category; use App\\CategoryFeature\\Domain\\Factory\\CategoryFactory as CategoryDomainFactory; use App\\DataManagerFeatureApi\\DTOResponse\\CategoryDataResponseInterface;  \/**  * Class CategoryDomainMapper  * @package App\\CategoryFeature\\Infrastructure\\DataMapper  **\/ class CategoryDomainMapper implements CategoryDomainMapperInterface {     private CategoryDomainFactory $categoryDomainFactory;      \/**      * @param CategoryDomainFactory $categoryDomainFactory      *\/     public function __construct(CategoryDomainFactory $categoryDomainFactory)     {         $this->categoryDomainFactory = $categoryDomainFactory;     }      \/**      * Map data response object to a domain object      * @param CategoryDataResponseInterface $dataResponse      * @return Category      *\/     public function map(CategoryDataResponseInterface $dataResponse): Category     {         return $this->categoryDomainFactory->create(             $dataResponse->getId(),             $dataResponse->getTitle(),             $dataResponse->getContent(),             $dataResponse->getSlug(),             $dataResponse->isActive()         );     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>CategoryRequestMapperInterface &#8212; \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0435\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\CategoryFeature\\Infrastructure\\DataMapper;  use App\\CategoryFeature\\Domain\\Entity\\Category; use App\\DataManagerFeatureApi\\DTORequest\\CategoryDataRequestInterface;  \/**  * Interface CategoryRequestMapperInterface  * Map domain object to a data object for sending to DataManagerFeature  * @package App\\CategoryFeature\\Infrastructure\\DataMapper  **\/ interface CategoryRequestMapperInterface {     \/**      * @param Category $domainEntity      * @return CategoryDataRequestInterface      *\/     public function map(Category $domainEntity): CategoryDataRequestInterface; } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>CategoryRequestMapper<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\CategoryFeature\\Infrastructure\\DataMapper;  use App\\CategoryFeature\\Domain\\Entity\\Category; use App\\DataManagerFeatureApi\\DTORequest\\CategoryDataRequestInterface; use App\\DataManagerFeatureApi\\DTORequestFactory\\CategoryDataRequestFactoryInterface;  \/**  * Class CategoryRequestMapper  * @package App\\CategoryFeature\\Infrastructure\\DataMapper  **\/ class CategoryRequestMapper implements CategoryRequestMapperInterface {     private CategoryDataRequestFactoryInterface $categoryDataRequestFactory;      \/**      * @param CategoryDataRequestFactoryInterface $categoryDataRequestFactory      *\/     public function __construct(CategoryDataRequestFactoryInterface $categoryDataRequestFactory)     {         $this->categoryDataRequestFactory = $categoryDataRequestFactory;     }      \/**      * Map domain object to a data object for sending to DataManagerFeature      * @param Category $domainEntity      * @return CategoryDataRequestInterface      *\/     public function map(Category $domainEntity): CategoryDataRequestInterface     {         $requestModel = $this->categoryDataRequestFactory->create();          $requestModel->setId($domainEntity->getId()->getValue());         $requestModel->setTitle($domainEntity->getTitle()->getValue());         $requestModel->setSlug($domainEntity->getSlug()->getValue());         $requestModel->setContent($domainEntity->getContent()->getValue());         $requestModel->setActive($domainEntity->isActive()->getValue());          return $requestModel;     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p><strong>Infrastructure layer (Repository)<\/strong><\/p>\n<details class=\"spoiler\">\n<summary>CategoryRepository<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\CategoryFeature\\Infrastructure\\Repository;  use App\\CategoryFeature\\Domain\\Entity\\Category; use App\\CategoryFeature\\Domain\\Repository\\CategoryRepositoryInterface; use App\\CategoryFeature\\Infrastructure\\DataMapper\\CategoryRequestMapperInterface; use App\\CategoryFeature\\Infrastructure\\DataMapper\\CategoryDomainMapperInterface; use App\\DataManagerFeatureApi\\Service\\CategoryDataServiceInterface;  \/**  * Class CategoryRepository  *  * We save data in another feature by doctrine.  * For that we need to convert a Category Domain Entity to a Data Manager request object,  * send that request object for saving to the Doctrine feature, get response object from the Doctrine Data Manager  * and convert that object back to a Domain entity.  *  * This approach allows you not to be depended on a concrete data storage.  * You can use Doctrine \/ Csv \/ Elastic if needed.  * Just create a separate module for each realisation and implement DataManagerFeatureApi.  * PS: don't forget to change interface realisation in construct.  *  * @package App\\CategoryFeature\\Infrastructure\\Repository  *\/ class CategoryRepository implements CategoryRepositoryInterface {     private CategoryDomainMapperInterface $categoryDomainMapper;     private CategoryRequestMapperInterface $categoryRequestDataMapper;     private CategoryDataServiceInterface $categoryDataService;      \/**      * @param CategoryDomainMapperInterface $domainMapper      * @param CategoryRequestMapperInterface $requestMapper      * @param CategoryDataServiceInterface $categoryDataService      *\/     public function __construct(         CategoryDomainMapperInterface  $domainMapper,         CategoryRequestMapperInterface $requestMapper,         CategoryDataServiceInterface   $categoryDataService     ) {         $this->categoryDomainMapper = $domainMapper;         $this->categoryRequestDataMapper = $requestMapper;         $this->categoryDataService = $categoryDataService;     }      \/**      * @param Category $category      * @return Category      *\/     public function save(Category $category): Category     {         $requestDTO = $this->categoryRequestDataMapper->map($category);         $responseDTO = $this->categoryDataService->save($requestDTO);          return $this->categoryDomainMapper->map($responseDTO);     }      \/**      * @param int $id      * @return void      *\/     public function deleteById(int $id): void     {         $this->categoryDataService->deleteById($id);     }      \/**      * @param array|null $criteria      * @return array      *\/     public function getList(array $criteria = null): array     {         $result = $this->categoryDataService->getList($criteria);         $list = [];          foreach ($result as $item) {             $list[] = $this->categoryDomainMapper->map($item);          }          return $list;     }      \/**      * @param int $id      * @return Category|null      *\/     public function getById(int $id): ?Category     {         $responseDTO = $this->categoryDataService->getById($id);         return $responseDTO ? $this->categoryDomainMapper->map($responseDTO) : null;     }      \/**      * @param string $slug      * @return Category|null      *\/     public function getBySlug(string $slug): ?Category     {         $responseDTO = $this->categoryDataService->getBySlug($slug);         return $responseDTO ? $this->categoryDomainMapper->map($responseDTO) : null;     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<hr\/>\n<h3>Application layer<\/h3>\n<p><strong>CategoryFeature (Application layer)<\/strong><\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/d41\/0e5\/739\/d410e573988c324c2ed6f1a1753f708a.png\" width=\"999\" height=\"622\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/d41\/0e5\/739\/d410e573988c324c2ed6f1a1753f708a.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0434\u043e\u043c\u0435\u043d\u043d\u043e\u0433\u043e \u0441\u043b\u043e\u044f \u0441\u043e \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 (\u0440\u0435\u043a\u0432\u0435\u0441\u0442 \u043e\u0431\u044a\u0435\u043a\u0442\u0430\u043c\u0438) \u0438 \u0440\u0435\u0441\u043f\u043e\u043d\u0441\u043e\u043c.<\/p>\n<p><strong>Application layer (ApiService)<\/strong><\/p>\n<details class=\"spoiler\">\n<summary>CategoryService &#8212; \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0435\u0439<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\CategoryFeature\\Application\\ApiService;  use App\\CategoryFeature\\Application\\DTODomainMapper\\CategoryMapperInterface as CategoryDomainMapper; use App\\CategoryFeature\\Application\\DTORequest\\CategoryRequestDTOInterface; use App\\CategoryFeature\\Application\\DTORequestValidator\\CategoryValidatorInterface; use App\\CategoryFeature\\Application\\DTOResponseMapper\\CategoryMapperInterface as CategoryDTOResponseMapper; use App\\CategoryFeature\\Application\\Model\\CategoryManagerInterface; use App\\CategoryFeatureApi\\DTORequest\\CategoryUpdateRequestInterface as UpdateRequest; use App\\CategoryFeatureApi\\DTORequest\\CategoryCreateRequestInterface as CreateRequest; use App\\CategoryFeatureApi\\DTOResponse\\CategoryDTOInterface as ResponseDTO; use App\\CategoryFeatureApi\\Service\\CategoryServiceInterface; use Exception;  \/**  * Class CategoryService  * @package App\\CategoryFeature\\Application\\ApiService  *  * This class is for external usage (outside this feature) only  * Use CategoryManagerInterface for data manipulating and return DTOResponse here  *  * Don't return Domain entity outside the feature!  *\/ class CategoryService implements CategoryServiceInterface {     private CategoryDTOResponseMapper $categoryDtoResponseMapper;     private CategoryDomainMapper $categoryDomainMapper;     private CategoryManagerInterface $categoryManager;     private CategoryValidatorInterface $categoryValidator;      \/**      * @param CategoryDTOResponseMapper $categoryDtoResponseMapper      * @param CategoryDomainMapper $categoryDomainMapper      * @param CategoryManagerInterface $categoryManager      * @param CategoryValidatorInterface $categoryValidator      *\/     public function __construct(         CategoryDTOResponseMapper $categoryDtoResponseMapper,         CategoryDomainMapper $categoryDomainMapper,         CategoryManagerInterface $categoryManager,         CategoryValidatorInterface $categoryValidator     ) {         $this->categoryDtoResponseMapper = $categoryDtoResponseMapper;         $this->categoryDomainMapper = $categoryDomainMapper;         $this->categoryManager = $categoryManager;         $this->categoryValidator = $categoryValidator;     }      \/**      * @param array|null $criteria      * @return array      *\/     public function getList(array $criteria = null): array     {         $list = [];         $categories = $this->categoryManager->getList($criteria);          foreach ($categories as $category) {             $list[] = $this->categoryDtoResponseMapper->map($category);         }          return $list;     }      \/**      * @param int $categoryId      * @return ResponseDTO|null      *\/     public function getById(int $categoryId): ?ResponseDTO     {         $category = $this->categoryManager->getById($categoryId);         return $category ? $this->categoryDtoResponseMapper->map($category) : null;     }      \/**      * @param string $slug      * @return ResponseDTO|null      *\/     public function getBySlug(string $slug): ?ResponseDTO     {         $category = $this->categoryManager->getBySlug($slug);         return $category ? $this->categoryDtoResponseMapper->map($category) : null;     }      \/**      * @return ResponseDTO      *\/     public function initNewCategory(): ResponseDTO     {         $category = $this->categoryManager->initNewCategory();         return $this->categoryDtoResponseMapper->map($category);     }      \/**      * @param CreateRequest $dtoRequest      * @return ResponseDTO      * @throws Exception      *\/     public function create(CreateRequest $dtoRequest): ResponseDTO     {         $this->validateRequest($dtoRequest);          $domainEntity = $this->categoryDomainMapper->mapCreateRequest($dtoRequest);         $createdCategory = $this->categoryManager->create($domainEntity);          return $this->categoryDtoResponseMapper->map($createdCategory);     }      \/**      * @param UpdateRequest $dtoRequest      * @return ResponseDTO      * @throws Exception      *\/     public function update(UpdateRequest $dtoRequest): ResponseDTO     {         $this->validateRequest($dtoRequest);          $domainEntity = $this->categoryDomainMapper->mapUpdateRequest($dtoRequest);         $updatedCategory = $this->categoryManager->update($domainEntity);          return $this->categoryDtoResponseMapper->map($updatedCategory);     }      \/**      * @param int $id      * @return void      *\/     public function deleteById(int $id): void     {         $this->categoryManager->deleteById($id);     }      \/**      * @param CategoryRequestDTOInterface $requestDTO      * @return void      * @throws Exception      *\/     protected function validateRequest(CategoryRequestDTOInterface $requestDTO): void     {         $errors = $this->categoryValidator->validate($requestDTO);         $message = \"\";          foreach ($errors as $property => $errorMsgs) {             $message .= \"The $property is not valid. Message: \" . implode(\",\" , $errorMsgs) . \" \\n\";         }          if ($message) {             throw new Exception($message);         }     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p><strong>Application layer (DTODomainMapper)<\/strong><\/p>\n<details class=\"spoiler\">\n<summary>CategoryMapperInterface &#8212; \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0432\u043d\u0443\u0442\u0440\u0438 \u0444\u0438\u0447\u0438<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\CategoryFeature\\Application\\DTODomainMapper;  use App\\CategoryFeature\\Domain\\Entity\\Category; use App\\CategoryFeatureApi\\DTORequest\\CategoryCreateRequestInterface; use App\\CategoryFeatureApi\\DTORequest\\CategoryUpdateRequestInterface;  \/**  * Interface CategoryMapperInterface  * Map DTO request to a Domain entity  *  * @package App\\CategoryFeature\\Application\\DTODomainMapper  **\/ interface CategoryMapperInterface {     \/**      * @param CategoryUpdateRequestInterface $dtoRequest      * @return Category      *\/     public function mapUpdateRequest(CategoryUpdateRequestInterface $dtoRequest): Category;      \/**      * @param CategoryCreateRequestInterface $dtoRequest      * @return Category      *\/     public function mapCreateRequest(CategoryCreateRequestInterface $dtoRequest): Category; } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>CategoryMapper &#8212; \u043c\u0430\u043f\u0438\u043c \u0440\u0435\u043a\u0432\u0435\u0441\u0442 \u0432 \u0434\u043e\u043c\u0435\u043d\u043d\u0443\u044e \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044c<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\CategoryFeature\\Application\\DTODomainMapper;  use App\\CategoryFeature\\Domain\\Entity\\Category; use App\\CategoryFeature\\Domain\\Factory\\CategoryFactory as CategoryDomainFactory; use App\\CategoryFeatureApi\\DTORequest\\CategoryCreateRequestInterface; use App\\CategoryFeatureApi\\DTORequest\\CategoryUpdateRequestInterface;  \/**  * Class CategoryMapper  * @package App\\CategoryFeature\\Application\\DTODomainMapper  **\/ class CategoryMapper implements CategoryMapperInterface {     private CategoryDomainFactory $categoryDomainFactory;      \/**      * @param CategoryDomainFactory $categoryDomainFactory      *\/     public function __construct(CategoryDomainFactory $categoryDomainFactory)     {         $this->categoryDomainFactory = $categoryDomainFactory;     }      \/**      * Map DTO request to a Domain entity      * @param CategoryUpdateRequestInterface $dtoRequest      * @return Category      *\/     public function mapUpdateRequest(CategoryUpdateRequestInterface $dtoRequest): Category     {         return $this->categoryDomainFactory->create(             $dtoRequest->getId(),             $dtoRequest->getTitle(),             $dtoRequest->getContent(),             $dtoRequest->getSlug(),             $dtoRequest->isActive()         );     }      \/**      * Map DTO request to a Domain entity      * @param CategoryCreateRequestInterface $dtoRequest      * @return Category      *\/     public function mapCreateRequest(CategoryCreateRequestInterface $dtoRequest): Category     {         return $this->categoryDomainFactory->create(             null,             $dtoRequest->getTitle(),             $dtoRequest->getContent(),             $dtoRequest->getSlug(),             $dtoRequest->isActive()         );     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p><strong>Application layer (DTORequest) &#8212; <\/strong>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b \u0434\u043b\u044f \u043f\u0435\u0440\u0432\u0438\u0447\u043d\u043e\u0439 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 \u0432\u0432\u043e\u0434\u0430. \u0422.\u0435. \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043d\u0430 \u0442\u0438\u043f\u044b\/\u043f\u0443\u0441\u0442\u043e\u0442\u0443 \u0438 \u0442\u0434. \u041d\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044e \u0431\u0438\u0437\u043d\u0435\u0441 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0432 \u0437\u0434\u0435\u0441\u044c<\/p>\n<details class=\"spoiler\">\n<summary>CategoryRequestDTOInterface &#8212; \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0435\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\CategoryFeature\\Application\\DTORequest;  \/**  * Interface CategoryRequestDTOInterface  * @package App\\CategoryFeature\\Application\\DTORequest  * Marker for Category DTO Requests  *\/ interface CategoryRequestDTOInterface {  } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>CategoryCreate &#8212; \u0440\u0435\u043a\u0432\u0435\u0441\u0442 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0438. <\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\CategoryFeature\\Application\\DTORequest;  use App\\CategoryFeatureApi\\DTORequest\\CategoryCreateRequestInterface; use Symfony\\Component\\Validator\\Constraints as Assert;  \/**  * Class CategoryCreate  * Request object for a category creation  *  * @package App\\CategoryFeature\\Application\\DTORequest  *\/ class CategoryCreate implements CategoryCreateRequestInterface, CategoryRequestDTOInterface {     #[Assert\\NotBlank]     #[Assert\\Type(\"string\")]     private ?string $title = null;      #[Assert\\Type(\"string\")]     private ?string $content = null;      #[Assert\\Type(\"string\")]     private ?string $slug = null;      #[Assert\\Type(\"bool\")]     private bool $isActive = false;      \/**      * @return string|null      *\/     public function getTitle(): ?string     {         return $this->title;     }      \/**      * @param string|null $title      *\/     public function setTitle(string $title = null): void     {         $this->title = $title;     }      \/**      * @return string|null      *\/     public function getContent(): ?string     {         return $this->content;     }      \/**      * @param string|null $content      *\/     public function setContent(string $content = null): void     {         $this->content = $content;     }      \/**      * @return string|null      *\/     public function getSlug(): ?string     {         return $this->slug;     }      \/**      * @param string|null $slug      *\/     public function setSlug(string $slug = null): void     {         $this->slug = $slug;     }      \/**      * @return bool      *\/     public function isActive(): bool     {         return $this->isActive;     }      \/**      * @param bool $active      *\/     public function setActive(bool $active): void     {         $this->isActive = $active;     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>CategoryUpdate<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\CategoryFeature\\Application\\DTORequest;  use App\\CategoryFeatureApi\\DTORequest\\CategoryUpdateRequestInterface; use Symfony\\Component\\Validator\\Constraints as Assert;  \/**  * Class CategoryUpdate  * Request object for a category updates  * @package App\\CategoryFeature\\Application\\DTORequest  *\/ class CategoryUpdate implements CategoryUpdateRequestInterface, CategoryRequestDTOInterface {     #[Assert\\NotBlank]     #[Assert\\Type(\"int\")]     private ?int $id = null;      #[Assert\\NotBlank]     #[Assert\\Type(\"string\")]     private ?string $title = null;      #[Assert\\Type(\"string\")]     private ?string $content = null;      #[Assert\\Type(\"string\")]     private ?string $slug = null;      #[Assert\\Type(\"bool\")]     private bool $isActive = false;      \/**      * @return int|null      *\/     public function getId(): ?int     {         return $this->id;     }      \/**      * @param int|null $id      *\/     public function setId(int $id = null): void     {         $this->id = $id;     }      \/**      * @return string|null      *\/     public function getTitle(): ?string     {         return $this->title;     }      \/**      * @param string|null $title      *\/     public function setTitle(string $title = null): void     {         $this->title = $title;     }      \/**      * @return string|null      *\/     public function getContent(): ?string     {         return $this->content;     }      \/**      * @param string|null $content      *\/     public function setContent(string $content = null): void     {         $this->content = $content;     }      \/**      * @return string|null      *\/     public function getSlug(): ?string     {         return $this->slug;     }      \/**      * @param string|null $slug      *\/     public function setSlug(string $slug = null): void     {         $this->slug = $slug;     }      \/**      * @return bool      *\/     public function isActive(): bool     {         return $this->isActive;     }      \/**      * @param bool $active      *\/     public function setActive(bool $active): void     {         $this->isActive = $active;     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p><strong>Application layer (DTORequestFactory) &#8212; \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0444\u0430\u0431\u0440\u0438\u043a<\/strong><\/p>\n<details class=\"spoiler\">\n<summary>CategoryCreateFactory<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\CategoryFeature\\Application\\DTORequestFactory;  use App\\CategoryFeature\\Application\\DTORequest\\CategoryCreate; use App\\CategoryFeatureApi\\DTORequest\\CategoryCreateRequestInterface; use App\\CategoryFeatureApi\\DTORequestFactory\\CategoryCreateDTOFactoryInterface;  \/**  * Class CategoryCreateFactory  * @package App\\CategoryFeature\\Application\\DTORequestFactory  *\/ class CategoryCreateFactory implements CategoryCreateDTOFactoryInterface {     \/**      * @return CategoryCreateRequestInterface      *\/     public function create(): CategoryCreateRequestInterface     {         return new CategoryCreate();     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>CategoryUpdateFactory<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\CategoryFeature\\Application\\DTORequestFactory;  use App\\CategoryFeature\\Application\\DTORequest\\CategoryUpdate; use App\\CategoryFeatureApi\\DTORequest\\CategoryUpdateRequestInterface; use App\\CategoryFeatureApi\\DTORequestFactory\\CategoryUpdateDTOFactoryInterface;  \/**  * Class CategoryUpdateFactory  * @package App\\CategoryFeature\\Application\\DTORequestFactory  *\/ class CategoryUpdateFactory implements CategoryUpdateDTOFactoryInterface {     \/**      * @return CategoryUpdateRequestInterface      *\/     public function create(): CategoryUpdateRequestInterface     {         return new CategoryUpdate();     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p><strong>Application layer (DTORequestValidator) &#8212; <\/strong>\u0432\u0430\u043b\u0438\u0434\u0430\u0442\u043e\u0440\u044b \u0434\u043b\u044f \u0440\u0435\u043a\u0432\u0435\u0441\u0442\u0430. \u0422.\u043a. \u0443 \u0441\u0438\u043c\u0444\u043e\u043d\u0438 \u0435\u0441\u0442\u044c \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0439 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u0434\u043b\u044f \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432, \u0442\u043e \u044f \u0441\u0434\u0435\u043b\u0430\u043b\u0430 \u043e\u0431\u0432\u0435\u0440\u0442\u043a\u0443 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430.<\/p>\n<details class=\"spoiler\">\n<summary>CategoryValidatorInterface &#8212; \u0434\u043b\u044f \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0435\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\CategoryFeature\\Application\\DTORequestValidator;  use App\\CategoryFeature\\Application\\DTORequest\\CategoryRequestDTOInterface;  \/**  * Interface CategoryValidatorInterface  * Primary request validation (input). Other validation must be in interactors.  * Interactors are responsible for business logic validation.  *  * @package App\\CategoryFeature\\Application\\DTORequestValidator  *\/ interface CategoryValidatorInterface {     \/**      * @param CategoryRequestDTOInterface $dto      * @return array      *\/     public function validate(CategoryRequestDTOInterface $dto): array; } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>CategoryValidator<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\CategoryFeature\\Application\\DTORequestValidator;  use App\\CategoryFeature\\Application\\DTORequest\\CategoryRequestDTOInterface; use Symfony\\Component\\Validator\\Validator\\ValidatorInterface;  \/**  * Class CategoryValidator  * @package App\\CategoryFeature\\Application\\DTORequestValidator  *\/ class CategoryValidator implements CategoryValidatorInterface {     private ValidatorInterface $validator;      \/**      * @param ValidatorInterface $validator      *\/     public function __construct(ValidatorInterface $validator)     {         $this->validator = $validator;     }      \/**      * Primary request validation (input). Other validation must be in interactors.      * Interactors are responsible for business logic validation.      *      * @param CategoryRequestDTOInterface $dto      * @return array      *\/     public function validate(CategoryRequestDTOInterface $dto): array     {         $violations = [];         $violationList = $this->validator->validate($dto);          foreach ($violationList as $violation) {             $violations[$violation->getPropertyPath()][] = $violation->getMessage();         }          return $violations;     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p><strong>Application layer (DTOResponse)<\/strong><\/p>\n<details class=\"spoiler\">\n<summary>Category<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\CategoryFeature\\Application\\DTOResponse;  use App\\CategoryFeatureApi\\DTOResponse\\CategoryDTOInterface;  \/**  * Class Category  * Module response object. This object will be returned for other features usage.  *  * @package App\\CategoryFeature\\Application\\DTOResponse;  **\/ class Category implements CategoryDTOInterface {     private ?int $id = null;     private ?string $title = null;     private ?string $content = null;     private ?string $slug = null;     private bool $isActive = false;      \/**      * @return int|null      *\/     public function getId(): ?int     {         return $this->id;     }      \/**      * @param int|null $id      *\/     public function setId(int $id = null): void     {         $this->id = $id;     }      \/**      * @return string|null      *\/     public function getTitle(): ?string     {         return $this->title;     }      \/**      * @param string|null $title      *\/     public function setTitle(string $title = null): void     {         $this->title = $title;     }      \/**      * @return string|null      *\/     public function getContent(): ?string     {         return $this->content;     }      \/**      * @param string|null $content      *\/     public function setContent(string $content = null): void     {         $this->content = $content;     }      \/**      * @return string      *\/     public function getSlug(): string     {         return $this->slug;     }      \/**      * @param string|null $slug      *\/     public function setSlug(string $slug = null): void     {         $this->slug = $slug;     }      \/**      * @return bool      *\/     public function isActive(): bool     {         return $this->isActive;     }      \/**      * @param bool $active      *\/     public function setActive(bool $active): void     {         $this->isActive = $active;     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p><strong>Application layer (DTOResponseFactory) &#8212; <\/strong>\u0434\u043b\u044f \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0435\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f<\/p>\n<details class=\"spoiler\">\n<summary>CategoryFactoryInterface<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\CategoryFeature\\Application\\DTOResponseFactory;  use App\\CategoryFeatureApi\\DTOResponse\\CategoryDTOInterface;  \/**  * Interface CategoryFactoryInterface  * @package App\\CategoryFeatureApi\\DTOResponseFactory  **\/ interface CategoryFactoryInterface {     \/**      * @return CategoryDTOInterface      *\/     public function create(): CategoryDTOInterface; } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>CategoryFactory<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\CategoryFeature\\Application\\DTOResponseFactory;  use App\\CategoryFeature\\Application\\DTOResponse\\Category; use App\\CategoryFeatureApi\\DTOResponse\\CategoryDTOInterface;  \/**  * Class CategoryFactory  * @package App\\CategoryFeature\\Application\\DTOResponseFactory  **\/ class CategoryFactory implements CategoryFactoryInterface {     \/**      * @return CategoryDTOInterface      *\/     public function create(): CategoryDTOInterface     {         return new Category();     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p><strong>Application layer (DTOResponseMapper) &#8212; <\/strong>\u0434\u043b\u044f \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0435\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f<\/p>\n<details class=\"spoiler\">\n<summary>CategoryMapperInterface<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\CategoryFeature\\Application\\DTOResponseMapper;  use App\\CategoryFeature\\Domain\\Entity\\Category; use App\\CategoryFeatureApi\\DTOResponse\\CategoryDTOInterface as CategoryResponseDTO;  \/**  * Interface CategoryMapperInterface  * Map domain entity to a Response DTO object.  * Don't return domain entity outside the module.  *  * @package App\\CategoryFeature\\Application\\DTOResponseMapper  **\/ interface CategoryMapperInterface {     \/**      * @param Category $category      * @return CategoryResponseDTO      *\/     public function map(Category $category): CategoryResponseDTO; } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>CategoryMapper<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\CategoryFeature\\Application\\DTOResponseMapper;  use App\\CategoryFeature\\Application\\DTOResponseFactory\\CategoryFactoryInterface; use App\\CategoryFeature\\Domain\\Entity\\Category; use App\\CategoryFeatureApi\\DTOResponse\\CategoryDTOInterface as CategoryResponseDTO;  \/**  * Class CategoryMapper  * @package App\\CategoryFeature\\Application\\DTOResponseMapper  **\/ class CategoryMapper implements CategoryMapperInterface {     private CategoryFactoryInterface $categoryDTOResponseFactory;      \/**      * @param CategoryFactoryInterface $categoryDTOResponseFactory      *\/     public function __construct(CategoryFactoryInterface $categoryDTOResponseFactory)     {         $this->categoryDTOResponseFactory = $categoryDTOResponseFactory;     }      \/**      * Map domain entity to a Response DTO object.      * Don't return domain entity outside the module.      *      * @param Category $category      * @return CategoryResponseDTO      *\/     public function map(Category $category): CategoryResponseDTO     {         $dtoResponse = $this->categoryDTOResponseFactory->create();          $dtoResponse->setActive($category->isActive()->getValue());         $dtoResponse->setId($category->getId()->getValue());         $dtoResponse->setContent($category->getContent()->getValue());         $dtoResponse->setSlug($category->getSlug()->getValue());         $dtoResponse->setTitle($category->getTitle()->getValue());          return $dtoResponse;     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p><strong>Application layer (Model) &#8212; <\/strong>\u0434\u043b\u044f \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0435\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f<\/p>\n<details class=\"spoiler\">\n<summary>CategoryManagerInterface<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\CategoryFeature\\Application\\Model;  use App\\CategoryFeature\\Domain\\Entity\\Category;  \/**  * Interface CategoryManagerInterface  * @package App\\CategoryFeature\\Application\\Model  **\/ interface CategoryManagerInterface {     \/**      * @param array|null $criteria      * @return array      *\/     public function getList(array $criteria = null): array;      \/**      * @param int $categoryId      * @return Category|null      *\/     public function getById(int $categoryId): ?Category;      \/**      * @param string $slug      * @return Category|null      *\/     public function getBySlug(string $slug): ?Category;      \/**      * @return Category      *\/     public function initNewCategory(): Category;      \/**      * @param Category $category      * @return Category      *\/     public function create(Category $category): Category;      \/**      * @param Category $category      * @return Category      *\/     public function update(Category $category): Category;      \/**      * @param int $id      * @return void      *\/     public function deleteById(int $id): void; } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>CategoryManager<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\CategoryFeature\\Application\\Model;  use App\\CategoryFeature\\Domain\\Entity\\Category; use App\\CategoryFeature\\Domain\\Interactor\\CategoryDeleteInteractor; use App\\CategoryFeature\\Domain\\Interactor\\CategoryLoadInteractor; use App\\CategoryFeature\\Domain\\Interactor\\CategorySaveInteractor;  \/**  * Class CategoryManager  * @package App\\CategoryFeature\\Application\\Model  *  * This class is for internal usage (inside this feature) only  **\/ class CategoryManager implements CategoryManagerInterface {     private CategorySaveInteractor $categorySaveInteractor;     private CategoryDeleteInteractor $categoryDeleteInteractor;     private CategoryLoadInteractor $categoryLoadInteractor;      \/**      * @param CategorySaveInteractor $categorySaveInteractor      * @param CategoryDeleteInteractor $categoryDeleteInteractor      * @param CategoryLoadInteractor $categoryLoadInteractor      *\/     public function __construct(         CategorySaveInteractor $categorySaveInteractor,         CategoryDeleteInteractor $categoryDeleteInteractor,         CategoryLoadInteractor $categoryLoadInteractor,     ) {         $this->categorySaveInteractor = $categorySaveInteractor;         $this->categoryDeleteInteractor = $categoryDeleteInteractor;         $this->categoryLoadInteractor = $categoryLoadInteractor;     }      \/**      * @param array|null $criteria      * @return array      *\/     public function getList(array $criteria = null): array     {         return $this->categoryLoadInteractor->loadAll($criteria);     }      \/**      * @param int $categoryId      * @return Category|null      *\/     public function getById(int $categoryId): ?Category     {         return $this->categoryLoadInteractor->loadById($categoryId);     }      \/**      * @param string $slug      * @return Category|null      *\/     public function getBySlug(string $slug): ?Category     {         return $this->categoryLoadInteractor->loadBySlug($slug);     }      \/**      * @return Category      *\/     public function initNewCategory(): Category     {         return $this->categoryLoadInteractor->loadEmptyCategory();     }      \/**      * @param Category $category      * @return Category      *\/     public function create(Category $category): Category     {         return $this->categorySaveInteractor->create($category);     }      \/**      * @param Category $category      * @return Category      *\/     public function update(Category $category): Category     {         return $this->categorySaveInteractor->update($category);     }      \/**      * @param int $id      * @return void      *\/     public function deleteById(int $id): void     {         $this->categoryDeleteInteractor->deleteById($id);     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0418 \u0442\u0430\u043a, \u0443 \u043d\u0430\u0441 \u0433\u043e\u0442\u043e\u0432\u0430 \u0444\u0438\u0447\u0430 \u0434\u043b\u044f \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0438!<\/p>\n<h2>PostFeature \u0438 PostFeatureApi<\/h2>\n<p><a class=\"anchor\" name=\"#post_feature\" id=\"#post_feature\"><\/a><\/p>\n<p>\u0417\u0434\u0435\u0441\u044c \u0431\u0443\u0434\u0435\u0442 \u0441\u0445\u043e\u0436\u0438\u0439 \u043f\u0440\u0438\u043d\u0446\u0438\u043f. \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u044f \u043d\u0435 \u0431\u0443\u0434\u0443 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0434\u0430\u043d\u043d\u043e\u0439 \u0444\u0438\u0447\u0438, \u0432\u0441\u0435 \u043a\u043b\u0430\u0441\u0441\u044b \u0432\u044b \u0441\u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0437\u0434\u0435\u0441\u044c &#8212;  <a href=\"https:\/\/github.com\/annysmolyan\/symfony-ddd-clean-architecture-blog\" rel=\"noopener noreferrer nofollow\">\u043f\u0440\u044f\u043c\u0430\u044f \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0433\u0438\u0442\u0445\u0430\u0431<\/a><\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c, \u043a\u043e\u0433\u0434\u0430 \u0443 \u043d\u0430\u0441 \u0433\u043e\u0442\u043e\u0432\u044b \u0444\u0438\u0447\u0438, \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u0444\u0440\u043e\u043d\u0442\u043e\u0432\u043e\u0439 \u0447\u0430\u0441\u0442\u0438.<\/p>\n<h2>FrontFeature<\/h2>\n<p><a class=\"anchor\" name=\"front\" id=\"front\"><\/a><\/p>\n<p>\u0417\u0434\u0435\u0441\u044c \u0438\u0434\u0435\u0442 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0444\u0440\u043e\u043d\u0442\u043e\u0432\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u041a\u0430\u043a \u043f\u0438\u0441\u0430\u043b\u043e\u0441\u044c \u0432\u044b\u0448\u0435, \u043d\u0435 \u0432\u0441\u0435 \u0444\u0438\u0447\u0438 \u043d\u0443\u0436\u0434\u0430\u044e\u0442\u0441\u044f \u0432\u043e \u0432\u0441\u0435\u0445 \u0441\u043b\u043e\u044f\u0445. \u0422\u0430\u043a, \u0442\u0430\u043a\u0438\u0435 \u0441\u043b\u043e\u0438, \u043a\u0430\u043a Application, Domain, Infrastructure \u0437\u0434\u0435\u0441\u044c \u043d\u0435 \u043d\u0443\u0436\u043d\u044b. \u0417\u0434\u0435\u0441\u044c \u043d\u0430\u043c \u043d\u0443\u0436\u0435\u043d \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u0438\u043d \u0441\u043b\u043e\u0439 &#8212; Presentation. \u0414\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0431\u0443\u0434\u0443\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f CategoryServiceInterface \u0438 PostServiceInterface, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u043e\u043f\u0438\u0441\u0430\u043b\u0438 \u0432 Api \u0444\u0438\u0447\u0430\u0445 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043c\u043e\u0434\u0443\u043b\u044f. \u0417\u0434\u0435\u0441\u044c \u0443 \u043d\u0430\u0441 \u0431\u0443\u0434\u0443\u0442 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u044b, \u0448\u0430\u0431\u043b\u043e\u043d\u044b.<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/38f\/38c\/bf2\/38f38cbf29f4ca037109e9be11a142c8.png\" width=\"493\" height=\"505\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/38f\/38c\/bf2\/38f38cbf29f4ca037109e9be11a142c8.png\"\/><figcaption><\/figcaption><\/figure>\n<h3>Presentation layer<\/h3>\n<p><strong>Presentation layer (Controller) &#8212; <\/strong>\u044f \u043f\u0440\u0435\u0432\u0435\u0440\u0436\u0435\u043d\u0435\u0446 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e 1 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 = 1 \u044d\u043a\u0448\u0435\u043d. \u0421\u0438\u043c\u0444\u043e\u043d\u0438 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c ADR pattern, \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0432\u0435\u043d\u043d\u043e \u043a\u0430\u0436\u0434\u044b\u0439 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u043c\u0435\u0442\u043e\u0434 __invoke() \u0438 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0437\u0430 1 \u044d\u043a\u0448\u0435\u043d. \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 <a href=\"https:\/\/symfony.com\/doc\/current\/controller\/service.html#invokable-controllers\" rel=\"noopener noreferrer nofollow\">\u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u0442\u0443\u0442<\/a><\/p>\n<p>\u041f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c \u043a \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044e \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u043e\u0432. \u0414\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0439 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438 \u0441\u0432\u043e\u044f \u043f\u0430\u043f\u043a\u0430, \u0433\u0434\u0435 \u0445\u0440\u0430\u043d\u044f\u0442\u044c\u0441\u044f \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u044b. \u0415\u0441\u043b\u0438 \u0445\u043e\u0442\u0438\u0442\u0435 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443, \u0433\u0434\u0435 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0432\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u0441\u043f\u0438\u0441\u043e\u043a \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0439, \u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c Category\\ListController. (\u0434\u0443\u043c\u0430\u044e, \u043b\u043e\u0433\u0438\u043a\u0430 \u0442\u0443\u0442 \u044f\u0441\u043d\u0430). <\/p>\n<details class=\"spoiler\">\n<summary>CategoryViewController<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\FrontFeature\\Presentation\\Controller\\Category;  use App\\CategoryFeatureApi\\Service\\CategoryServiceInterface; use App\\PostFeatureApi\\Service\\PostServiceInterface; use Symfony\\Bundle\\FrameworkBundle\\Controller\\AbstractController; use Symfony\\Component\\HttpFoundation\\Response; use Symfony\\Component\\Routing\\Annotation\\Route;  \/**  * Class ViewController  * @package App\\FrontFeature\\Presentation\\Controller\\Category  *  * WARNING! Presentation layer can communicate ONLY with Application layer or shared API.  * Presentation layer doesn't know anything about domain  *\/ #[Route('\/category', name: 'frontend_feature_category_')] class ViewController extends AbstractController {     private CategoryServiceInterface $categoryService;     private PostServiceInterface $postService;      \/**      * @param PostServiceInterface $postService      * @param CategoryServiceInterface $categoryService      *\/     public function __construct(         PostServiceInterface $postService,         CategoryServiceInterface $categoryService     ) {         $this->categoryService = $categoryService;         $this->postService = $postService;     }      #[Route('\/{slug}', name: 'view', methods: [\"GET\"])]     public function __invoke(string $slug): Response     {         $category = $this->categoryService->getBySlug($slug);          if (null === $category) {             throw $this->createNotFoundException();         }          return $this->render('@frontend_feature_templates\/baseTheme\/layout\/category\/view.html.twig', [             'category' => $category,             'menuItems' => $this->categoryService->getList([\"isActive\" => true]),             'seoTitle' => $category->getTitle(),             'seoDescription' => $category->getTitle(),             'postList' => $this->postService->getList(['category' => $category->getId(), 'isPublished' => true]),         ]);     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>HomeViewController<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\FrontFeature\\Presentation\\Controller\\Home;  use App\\CategoryFeatureApi\\Service\\CategoryServiceInterface; use Symfony\\Bundle\\FrameworkBundle\\Controller\\AbstractController; use Symfony\\Component\\HttpFoundation\\Response; use Symfony\\Component\\Routing\\Annotation\\Route;  \/**  * Class ViewController  * @package App\\FrontFeature\\Presentation\\Controller\\Home  *  * WARNING! Presentation layer can communicate ONLY with Application layer or shared API.  * Presentation layer doesn't know anything about domain  *\/ class ViewController extends AbstractController {     private const PAGE_TITLE = \"Symfony Blog: Learn Clean Architecture Together\";     private const PAGE_DESCRIPTION = \"Learn Clean Architecture Together\";      private CategoryServiceInterface $categoryService;      \/**      * @param CategoryServiceInterface $categoryService      *\/     public function __construct(CategoryServiceInterface $categoryService)     {         $this->categoryService = $categoryService;     }      #[Route('\/', name: 'home', methods: [\"GET\"])]     public function __invoke(): Response     {         $categoryList = $this->categoryService->getList([\"isActive\" => true]);          return $this->render('@frontend_feature_templates\/baseTheme\/layout\/home\/view.html.twig', [             'categoryList' => $categoryList,             'seoTitle' => self::PAGE_TITLE,             'seoDescription' => self::PAGE_DESCRIPTION,             'menuItems' => $categoryList         ]);     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>PostViewController<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php \/**  * NOTICE OF LICENSE  *  * This source file is subject to the GNU General Public License v3 (GPL 3.0)  * It is available through the world-wide-web at this URL:  * https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html  *  * @license    https:\/\/www.gnu.org\/licenses\/gpl-3.0.en.html GNU General Public License v3 (GPL 3.0)  *\/  declare(strict_types=1);  namespace App\\FrontFeature\\Presentation\\Controller\\Post;  use App\\CategoryFeatureApi\\Service\\CategoryServiceInterface; use App\\PostFeatureApi\\Service\\PostServiceInterface; use Symfony\\Bundle\\FrameworkBundle\\Controller\\AbstractController; use Symfony\\Component\\HttpFoundation\\Response; use Symfony\\Component\\Routing\\Annotation\\Route;  \/**  * Class ViewController  * @package App\\FrontFeature\\Presentation\\Controller\\Post  *  * WARNING! Presentation layer can communicate ONLY with Application layer or shared API.  * Presentation layer doesn't know anything about domain  *\/ #[Route('\/post', name: 'frontend_feature_post_')] class ViewController extends AbstractController {     private PostServiceInterface $postService;     private CategoryServiceInterface $categoryService;      \/**      * @param CategoryServiceInterface $categoryService      * @param PostServiceInterface $postService      *\/     public function __construct(         CategoryServiceInterface $categoryService,         PostServiceInterface $postService     ) {         $this->postService = $postService;         $this->categoryService = $categoryService;     }      #[Route('\/{slug}', name: 'view', methods: [\"GET\"])]     public function __invoke(string $slug): Response     {         $post = $this->postService->getBySlug($slug);          if (null === $post) {             throw $this->createNotFoundException();         }          return $this->render('@frontend_feature_templates\/baseTheme\/layout\/post\/view.html.twig', [             'post' => $post,             'menuItems' => $this->categoryService->getList([\"isActive\" => true]),             'seoTitle' => $post->getTitle(),             'seoDescription' => $post->getTitle(),         ]);     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0447\u0442\u043e \u043f\u0440\u0438 \u0440\u0435\u043d\u0434\u0435\u0440\u0435 \u0448\u0430\u0431\u043b\u043e\u043d\u0430 \u0441\u0442\u043e\u0438\u0442 &#171;[dog]frontend_feature_templates&#187;. \u0417\u0430\u0431\u0435\u0433\u0430\u044f \u043d\u0430\u043f\u0435\u0440\u0435\u0434 \u0441\u043a\u0430\u0436\u0443, \u0447\u0442\u043e \u0442\u043a \u043c\u044b \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0435 \u0444\u043e\u043b\u0434\u0435\u0440\u044b \u0441\u0438\u043c\u0444\u043e\u043d\u0438, \u0442\u043e \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0443\u043a\u0430\u0437\u0430\u0442\u044c, \u0433\u0434\u0435 \u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c twig \u0448\u0430\u0431\u043b\u043e\u043d\u044b. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e, \u043d\u0443\u0436\u043d\u043e \u0437\u0430\u0439\u0442\u0438 \u0432 \u043a\u043e\u043d\u0444\u0438\u0433 <strong>config\/packages\/twig.yaml<\/strong>  \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043f\u0443\u0442\u0438:<\/p>\n<pre><code>twig:     default_path: '%kernel.project_dir%\/templates'     paths:         'src\/FrontFeature\/Presentation\/view': 'frontend_feature_templates' #new folder  when@test:     twig:         strict_variables: true <\/code><\/pre>\n<p>\u0422\u0430\u043a\u0436\u0435 \u043d\u0430\u0448\u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u044b \u043d\u0435 \u0431\u0443\u0434\u0443\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c, \u0442\u043a \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u0432 \u0434\u0440\u0443\u0433\u043e\u0439 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0438\u0434\u0435\u043c \u0432 <strong>config\/routes.yaml :<\/strong><\/p>\n<pre><code>#controllers: #    resource: #        path: ..\/src\/Controller\/ #        namespace: App\\Controller #    type: attribute  frontend_feature_controllers:     resource: '..\/src\/FrontFeature\/Presentation\/Controller\/'     type: attribute     trailing_slash_on_root: false <\/code><\/pre>\n<p><strong>Presentation layer (view)  &#8212; <\/strong>\u044f \u0442\u0430\u043a\u0436\u0435 \u043f\u043e\u0441\u0442\u0430\u0440\u0430\u043b\u0430\u0441\u044c \u043e\u0442\u0434\u0435\u043b\u0438\u0442\u044c \u0442\u0435\u043c\u044b \u0434\u0440\u0443\u0433 \u043e\u0442 \u0434\u0440\u0443\u0433\u0430. \u041e\u0441\u043d\u043e\u0432\u043d\u0443\u044e \u0442\u0435\u043c\u0443 \u043f\u043e\u043c\u0435\u0441\u0442\u0438\u043b\u0430 \u0432\u043e view\/baseTheme. \u042f \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e \u0437\u0434\u0435\u0441\u044c Encore, \u0442\u043a \u044d\u0442\u043e\u0442 \u0431\u043b\u043e\u0433 \u043d\u0430\u043f\u0438\u0441\u0430\u043d \u0432 \u0446\u0435\u043b\u044f\u0445 \u0438\u0437\u0443\u0447\u0435\u043d\u0438\u044f \u0447\u0438\u0441\u0442\u043e\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b. \u041f\u043e \u044d\u0442\u043e\u043c\u0443, \u044f \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u0443\u043f\u0440\u043e\u0441\u0442\u0438\u043b\u0430 \u0442\u0435\u043c\u0443. \u0412\u044b \u0441\u043c\u043e\u0436\u0435\u0442\u0435 \u0441\u0430\u043c\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0444\u0440\u043e\u043d\u0442 \u043f\u043e \u0441\u0432\u043e\u0435\u043c\u0443 \u0443\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u0438\u044e.<\/p>\n<p><strong>Presentation layer (<\/strong>view\/baseTheme\/block<strong>) &#8212; <\/strong>\u0437\u0434\u0435\u0441\u044c \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0431\u043b\u043e\u043a\u0438 \u0442\u0435\u043c\u044b<\/p>\n<details class=\"spoiler\">\n<summary>footer.html.twig<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>&lt;p>This is blog footer&lt;\/p><\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>head.html.twig<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>&lt;head>     &lt;meta charset=\"UTF-8\">     &lt;title>         {% block seoTitle %}{{ seoTitle }}{% endblock %}     &lt;\/title>     &lt;meta name=\"description\" content=\"{% block seoDescription %}{{ seoDescription }}{% endblock %}\">     &lt;meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">     &lt;link rel=\"stylesheet\" href=\"https:\/\/cdn.jsdelivr.net\/npm\/bootstrap@5.2.3\/dist\/css\/bootstrap.min.css\" integrity=\"sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65\" crossorigin=\"anonymous\">     &lt;link rel=\"icon\"           href=\"data:image\/svg+xml,&lt;svg xmlns=%22http:\/\/www.w3.org\/2000\/svg%22 viewBox=%220 0 128 128%22>&lt;text y=%221.2em%22 font-size=%2296%22>\u26ab\ufe0f&lt;\/text>&lt;\/svg>\"     >      {% block stylesheets %}         {{ encore_entry_link_tags('app') }}     {% endblock %}      {% block javascripts %}         {{ encore_entry_script_tags('app') }}     {% endblock %} &lt;\/head>  &lt;style>     .bd-placeholder-img {         font-size: 1.125rem;         text-anchor: middle;         -webkit-user-select: none;         -moz-user-select: none;         user-select: none;     }      @media (min-width: 768px) {         .bd-placeholder-img-lg {             font-size: 3.5rem;         }     }      .b-example-divider {         height: 3rem;         background-color: rgba(0, 0, 0, .1);         border: solid rgba(0, 0, 0, .15);         border-width: 1px 0;         box-shadow: inset 0 .5em 1.5em rgba(0, 0, 0, .1), inset 0 .125em .5em rgba(0, 0, 0, .15);     }      .b-example-vr {         flex-shrink: 0;         width: 1.5rem;         height: 100vh;     }      .bi {         vertical-align: -.125em;         fill: currentColor;     }      .nav-scroller {         position: relative;         z-index: 2;         height: 2.75rem;         overflow-y: hidden;     }      .nav-scroller .nav {         display: flex;         flex-wrap: nowrap;         padding-bottom: 1rem;         margin-top: -1px;         overflow-x: auto;         text-align: center;         white-space: nowrap;         -webkit-overflow-scrolling: touch;     }      \/* stylelint-disable selector-list-comma-newline-after *\/      .blog-header {         border-bottom: 1px solid #e5e5e5;     }      .blog-header-logo {         font-family: \"Playfair Display\", Georgia, \"Times New Roman\", serif\/*rtl:Amiri, Georgia, \"Times New Roman\", serif*\/;         font-size: 2.25rem;     }      .blog-header-logo:hover {         text-decoration: none;     }      h1, h2, h3, h4, h5, h6 {         font-family: \"Playfair Display\", Georgia, \"Times New Roman\", serif\/*rtl:Amiri, Georgia, \"Times New Roman\", serif*\/;     }      .display-4 {         font-size: 2.5rem;     }     @media (min-width: 768px) {         .display-4 {             font-size: 3rem;         }     }      .flex-auto {         flex: 0 0 auto;     }      .h-250 { height: 250px; }     @media (min-width: 768px) {         .h-md-250 { height: 250px; }     }      \/* Pagination *\/     .blog-pagination {         margin-bottom: 4rem;     }      \/*      * Blog posts      *\/     .blog-post {         margin-bottom: 4rem;     }     .blog-post-title {         font-size: 2.5rem;     }     .blog-post-meta {         margin-bottom: 1.25rem;         color: #727272;     }      \/*      * Footer      *\/     .blog-footer {         padding: 2.5rem 0;         color: #727272;         text-align: center;         background-color: #f9f9f9;         border-top: .05rem solid #e5e5e5;     }     .blog-footer p:last-child {         margin-bottom: 0;     } &lt;\/style>  <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>header.html.twig<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>&lt;div class=\"row flex-nowrap justify-content-between align-items-center\">     &lt;div class=\"col-12 text-center\">         &lt;a class=\"blog-header-logo text-dark\" href=\"\/\">Clean Architecture Blog&lt;\/a>     &lt;\/div> &lt;\/div> <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p><strong>Presentation layer (<\/strong>view\/baseTheme\/layout<strong>) &#8212; <\/strong>\u0437\u0434\u0435\u0441\u044c \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043c\u0430\u043a\u0435\u0442\u044b \u0434\u043b\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446<\/p>\n<details class=\"spoiler\">\n<summary>category\/view.html.twig<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>{% extends '@frontend_feature_templates\/baseTheme\/layout\/base.html.twig' %}  {% block pageTitle %}     {{category.title}} {% endblock %}  {% block main %}     &lt;div class=\"row g-5\">         &lt;div class=\"col-md-12\">             &lt;article class=\"blog-post\">                 {{ category.content }}             &lt;\/article>         &lt;\/div>     &lt;\/div>     &lt;div class=\"row mb-2\">         {% if postList %}             {% for post in postList %}                 &lt;div class=\"col-md-6\">                     &lt;div class=\"row g-0 border rounded overflow-hidden flex-md-row mb-4 shadow-sm h-md-250 position-relative\">                         &lt;div class=\"col p-4 d-flex flex-column position-static\">                             &lt;h3 class=\"mb-0\">{{ post.title }}&lt;\/h3>                             &lt;a                                     href=\"{{ path('frontend_feature_post_view', {slug: post.slug}) }}\"                                     class=\"stretched-link\"                             >                                 Continue reading                             &lt;\/a>                         &lt;\/div>                     &lt;\/div>                 &lt;\/div>             {% endfor %}         {% else %}             &lt;p>No posts yet =(&lt;\/p>         {% endif %}     &lt;\/div> {% endblock %} <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>home\/view.html.twig<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>{% extends '@frontend_feature_templates\/baseTheme\/layout\/base.html.twig' %}  {% block pageTitle %}     Welcome! Glad To See You Here! {% endblock %}  {% block main %}     &lt;div class=\"row mb-2\">         {% for category in categoryList %}             &lt;div class=\"col-md-6\">                 &lt;div class=\"row g-0 border rounded overflow-hidden flex-md-row mb-4 shadow-sm h-md-250 position-relative\">                     &lt;div class=\"col p-4 d-flex flex-column position-static\">                         &lt;h3 class=\"mb-0\">{{ category.title }}&lt;\/h3>                         &lt;a                                 href=\"{{ path('frontend_feature_category_view', {slug: category.slug}) }}\"                                 class=\"stretched-link\"                         >                             Continue reading                         &lt;\/a>                     &lt;\/div>                 &lt;\/div>             &lt;\/div>         {% endfor %}     &lt;\/div> {% endblock %} <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>post\/view.html.twig<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>{% extends '@frontend_feature_templates\/baseTheme\/layout\/base.html.twig' %}  {% block pageTitle %}     {{post.title}} {% endblock %}  {% block main %}     &lt;div class=\"row g-5\">         &lt;div class=\"col-md-8\">             &lt;article class=\"blog-post\">                 &lt;p class=\"blog-post-meta\">{{ post.updatedAt }}&lt;\/p>                 {{ post.content }}             &lt;\/article>         &lt;\/div>         &lt;div class=\"col-md-4\">             &lt;div class=\"position-sticky\" style=\"top: 2rem;\">                 &lt;div class=\"p-4\">                     &lt;h4 class=\"fst-italic\">Categories&lt;\/h4>                     &lt;ol class=\"list-unstyled mb-0\">                         {% for item in menuItems %}                             &lt;li>                                 &lt;a                                     class=\"p-2 link-secondary\"                                     href=\"{{ path('frontend_feature_category_view', {slug: item.slug}) }}\"                                 >                                     {{ item.title }}                                 &lt;\/a>                             &lt;\/li>                         {% endfor %}                     &lt;\/ol>                 &lt;\/div>             &lt;\/div>         &lt;\/div>     &lt;\/div> {% endblock %} <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>base.html.twig &#8212; \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u043c\u0430\u043a\u0435\u0442, \u043e\u0442 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u044e\u0442\u0441\u044f \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>&lt;!DOCTYPE html> &lt;html lang=\"en\">     {%         include '@frontend_feature_templates\/baseTheme\/block\/head.html.twig'         with {             'seoTitle': (seoTitle is defined) ? seoTitle : 'Default Title',             'seoDescription': (seoDescription is defined) ? seoDescription : 'Default Description'         }     %}     &lt;body>         {% block body %}             &lt;div class=\"container\">                 &lt;header class=\"{% block headerClass %}blog-header lh-1 py-3{% endblock %}\">                     {% block header %}                         {% include '@frontend_feature_templates\/baseTheme\/block\/header.html.twig' %}                     {% endblock %}                 &lt;\/header>                  &lt;div class=\"{% block blockNavWrapperClass %}nav-scroller py-1 mb-2{% endblock %}\">                     {% block nav %}                         &lt;nav class=\"nav d-flex justify-content-between\">                             {% for item in menuItems %}                                 &lt;a                                     class=\"p-2 link-secondary\"                                     href=\"{{ path('frontend_feature_category_view', {slug: item.slug}) }}\">                                     {{ item.title }}                                 &lt;\/a>                             {% endfor %}                         &lt;\/nav>                     {% endblock %}                 &lt;\/div>             &lt;\/div>              &lt;main class=\"{% block blockMainWrapperClass %}container{% endblock %}\">                 &lt;div class=\"p-4 p-md-5 mb-4 rounded text-bg-dark\">                     &lt;div class=\"col-md-12 px-0\">                         &lt;h1 class=\" fst-italic\">{% block pageTitle %}{% endblock %}&lt;\/h1>                     &lt;\/div>                 &lt;\/div>                 {% block main %}{% endblock %}             &lt;\/main>              &lt;footer class=\"{% block blockFooterWrapperClass %}blog-footer{% endblock %}\">                 {% block footer %}                     {% include '@frontend_feature_templates\/baseTheme\/block\/footer.html.twig' %}                 {% endblock %}             &lt;\/footer>         {% endblock %}     &lt;\/body> &lt;\/html> <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<hr\/>\n<h2>\u0418\u0442\u043e\u0433\u043e\u0432\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442<\/h2>\n<p><a class=\"anchor\" name=\"the_end\" id=\"the_end\"><\/a><\/p>\n<p>\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u0448\u0442\u0440\u0438\u0445 &#8212; \u044d\u0442\u043e \u043f\u043e\u043f\u0440\u0430\u0432\u0438\u0442\u044c <strong>config\/services.yaml. <\/strong>\u041d\u0435 \u0437\u0430\u0431\u0443\u0434\u044c\u0442\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0441\u0435\u0440\u0432\u0438\u0441\u044b \u0438 \u043f\u0440\u043e\u043f\u0438\u0441\u0430\u0442\u044c DI:<\/p>\n<pre><code>    App\\CategoryFeature\\:         resource: '..\/src\/CategoryFeature\/'         exclude:             - '..\/src\/CategoryFeature\/Domain'      App\\CategoryFeatureApi\\:         resource: '..\/src\/CategoryFeatureApi\/'      App\\DoctrineDataFeature\\:         resource: '..\/src\/DoctrineDataFeature\/'         exclude:             - '..\/src\/DoctrineDataFeature\/Domain'      App\\DataManagerFeatureApi\\:         resource: '..\/src\/DataManagerFeatureApi\/'      App\\PostFeatureApi\\:         resource: '..\/src\/PostFeatureApi\/'      App\\PostFeature\\:         resource: '..\/src\/PostFeature\/'      ##### DI Area #####     App\\DoctrineDataFeature\\Application\\ApiService\\CategoryService:         arguments:             $dataMapper: '@App\\DoctrineDataFeature\\Application\\DataMapper\\CategoryMapper'             $categoryRepository: '@App\\DoctrineDataFeature\\Infrastructure\\Repository\\CategoryRepository'      App\\DoctrineDataFeature\\Application\\ApiService\\PostService:         arguments:             $dataMapper: '@App\\DoctrineDataFeature\\Application\\DataMapper\\PostMapper'             $postRepository: '@App\\DoctrineDataFeature\\Infrastructure\\Repository\\PostRepository'<\/code><\/pre>\n<p>\u0418 \u0442\u0430\u043a, \u043a\u043e\u0433\u0434\u0430 \u0432\u0441\u0435 \u0444\u0438\u0447\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u044b, \u043d\u0430\u043c \u043e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0441\u0430\u0439\u0442 \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u043e\u043c \u0438 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0437\u0430\u043f\u043e\u043b\u043d\u0438\u043c \u0441\u0430\u0439\u0442 \u0444\u0435\u0439\u043a\u043e\u0432\u044b\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u043c\u0438, \u0438 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u043a\u0430\u043a \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c.<\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043f\u0430\u0440\u0443 \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0439:<\/p>\n<pre><code class=\"php\">use App\\CategoryFeatureApi\\Service\\CategoryServiceInterface; use App\\CategoryFeatureApi\\DTORequestFactory\\CategoryCreateDTOFactoryInterface;  private CategoryServiceInterface $categoryService; private CategoryCreateDTOFactoryInterface $categoryCreateDTOFactory;   $categoryRequest = $this->createRequestFactory->create(); $categoryRequest->setTitle(\"My first category\"); $categoryRequest->setSlug(\"test-slug\"); $categoryRequest->setContent(\"Dummy category content\"); $categoryRequest->setActive(true);  $this->categoryService->create($categoryRequest);  \u0438 \u0442\u0434.<\/code><\/pre>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043f\u0430\u0440\u0443 \u043f\u043e\u0441\u0442\u043e\u0432:<\/p>\n<pre><code class=\"php\">use App\\PostFeatureApi\\DTORequestFactory\\PostCreateDTOFactoryInterface; use App\\PostFeatureApi\\Service\\PostServiceInterface;   private PostCreateDTOFactoryInterface $postCreateDTOFactory; private PostServiceInterface $postService;  $postRequest = $this->postCreateDTOFactory->create(); $postRequest->setSlug(\"my-test-slug\"); $postRequest->setTitle(\"My dummy title\"); $postRequest->setContent(\"This is dummy content\"); $postRequest->setPublished(true); $postRequest->setCategoryId(1);  $this->postService->create($postRequest);  \u0438 \u0442\u0434.<\/code><\/pre>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/056\/c16\/742\/056c1674229b35b46eaab41e91b020f1.png\" alt=\"\u0413\u043b\u0430\u0432\u043d\u0430\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430\" title=\"\u0413\u043b\u0430\u0432\u043d\u0430\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430\" width=\"1390\" height=\"855\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/056\/c16\/742\/056c1674229b35b46eaab41e91b020f1.png\"\/><figcaption>\u0413\u043b\u0430\u0432\u043d\u0430\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430<\/figcaption><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/2f5\/284\/1fd\/2f52841fdd5f6c75011df126d5041e58.png\" alt=\"\u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0438\" title=\"\u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0438\" width=\"1210\" height=\"905\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/2f5\/284\/1fd\/2f52841fdd5f6c75011df126d5041e58.png\"\/><figcaption>\u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0438<\/figcaption><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/00a\/461\/2a1\/00a4612a1dbccf32d69367f8e5535001.png\" alt=\"\u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u0441 \u043f\u043e\u0441\u0442\u043e\u043c\" title=\"\u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u0441 \u043f\u043e\u0441\u0442\u043e\u043c\" width=\"1224\" height=\"607\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/00a\/461\/2a1\/00a4612a1dbccf32d69367f8e5535001.png\"\/><figcaption>\u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u0441 \u043f\u043e\u0441\u0442\u043e\u043c<\/figcaption><\/figure>\n<p>\u041d\u0430 \u044d\u0442\u043e\u043c \u0432\u0441\u0435. \u0423 \u043d\u0430\u0441 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438\u0441\u044c \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u044b\u0435 \u0444\u0438\u0447\u0438 \u0434\u0440\u0443\u0433 \u043e\u0442 \u0434\u0440\u0443\u0433\u0430, \u043c\u044b \u0442\u0430\u043a\u0436\u0435 \u043d\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c \u043e\u0442 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445. \u041e\u0431\u0449\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u043e \u0441\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043c \u0410\u041f\u0418. \u0418 \u0432 \u0446\u0435\u043b\u043e\u043c, \u0435\u0441\u043b\u0438 \u0437\u0430\u0445\u043e\u0447\u0435\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0442\u0438 \u043a\u043e\u0434 \u043d\u0430 \u0434\u0440\u0443\u0433\u043e\u0439 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a, \u0442\u043e \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u0438 \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0431\u0435\u0437 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439.<\/p>\n<p>\u041f\u043e\u043b\u043d\u044b\u0435 \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438 \u0437\u0434\u0435\u0441\u044c &#8212;  <a href=\"https:\/\/github.com\/annysmolyan\/symfony-ddd-clean-architecture-blog\" rel=\"noopener noreferrer nofollow\">\u043f\u0440\u044f\u043c\u0430\u044f \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0433\u0438\u0442\u0445\u0430\u0431<\/a><\/p>\n<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p> <!----> <!----><\/div>\n<p> <!----> <!----><br \/> \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\/post\/718916\/\"> https:\/\/habr.com\/ru\/post\/718916\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0412\u0441\u0435\u043c \u043f\u0440\u0438\u0432\u0435\u0442! \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \ud83d\ude09 \u042f \u0410\u043d\u044f, \u0438 \u044f php \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a. \u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0441\u0442\u0435\u043a &#8212; Magento. \u0421 \u043d\u0435\u0434\u0430\u0432\u043d\u0438\u0445 \u043f\u043e\u0440 \u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u043e\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0442\u044c <s>\u043d\u0430\u043b\u0435\u0432\u043e<\/s> \u043d\u0430 Symfony \u0438 \u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u0438 Pet Projects \u043d\u0430 \u044d\u0442\u043e\u043c \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0435.  <\/p>\n<p>\u041c\u043d\u0435 \u0432\u0441\u0435\u0433\u0434\u0430 \u043d\u0440\u0430\u0432\u0438\u043b\u043e\u0441\u044c \u043f\u0438\u0441\u0430\u0442\u044c \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043b\u0435\u0433\u043a\u043e \u0431\u044b \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u043b\u0438\u0441\u044c \/ \u0430\u0434\u0430\u043f\u0442\u0438\u0440\u043e\u0432\u0430\u043b\u0438\u0441\u044c \u043f\u043e\u0434 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u0431\u0438\u0437\u043d\u0435\u0441\u0430 (\u0437\u0430\u043a\u0430\u0437\u0447\u0438\u043a\u0430). \u0418 \u043c\u043d\u0435 \u0432\u0441\u0435\u0433\u0434\u0430 \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u044d\u0442\u043e \u0431\u043e\u043b\u0435\u0435 &#8216;\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e&#8217; \u0438 \u043a\u0440\u0430\u0441\u0438\u0432\u043e. \u0422\u0430\u043a \u044f \u0438 \u043f\u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u043b\u0430\u0441\u044c \u0441 \u043f\u043e\u043d\u044f\u0442\u0438\u044f\u043c\u0438  \u0447\u0438\u0441\u0442\u043e\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043e\u0439.<\/p>\n<p>\u041c\u043e\u0439 \u043f\u043e\u0441\u0442 \u043d\u0438 \u0432 \u043a\u043e\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043d\u0435 \u043f\u0440\u0435\u0442\u0435\u043d\u0434\u0443\u0435\u0442 \u043d\u0430 \u0441\u0430\u043c\u044b\u0439 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0439. \u041d\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044c\u0442\u0435 \u043c\u043d\u0435 \u0437\u0434\u0435\u0441\u044c \u0434\u043e\u043d\u0435\u0441\u0442\u0438 \u0441\u0432\u043e\u0438 \u0438\u0434\u0435\u0438. \u0412 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u0445 \u0431\u0443\u0434\u0443 \u0440\u0430\u0434\u0430 \u0443\u0441\u043b\u044b\u0448\u0430\u0442\u044c \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u0438\u0432\u043d\u0443\u044e \u043a\u0440\u0438\u0442\u0438\u043a\u0443 \u043a \u0434\u0430\u043d\u043d\u043e\u043c\u0443 \u043f\u043e\u0441\u0442\u0443. <\/p>\n<p>\u0414\u043b\u044f \u043d\u0435\u0442\u0435\u0440\u043f\u0435\u043b\u0438\u0432\u044b\u0445, \u0432\u043e\u0442 <a href=\"https:\/\/github.com\/annysmolyan\/symfony-ddd-clean-architecture-blog\" rel=\"noopener noreferrer nofollow\">\u043f\u0440\u044f\u043c\u0430\u044f \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0433\u0438\u0442\u0445\u0430\u0431<\/a><\/p>\n<h2>\u0421\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435 \u0441\u0442\u0430\u0442\u044c\u0438 (\u0422\u0435\u043e\u0440\u0435\u0442\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u0447\u0430\u0441\u0442\u044c)<\/h2>\n<ol>\n<li>\n<p><a href=\"#ddd\" rel=\"noopener noreferrer nofollow\">\u0427\u0442\u043e \u0442\u0430\u043a\u043e\u0435 DDD<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#hexagonal\" rel=\"noopener noreferrer nofollow\">\u0427\u0442\u043e \u0442\u0430\u043a\u043e\u0435 \u0433\u0435\u043a\u0441\u0430\u0433\u043e\u043d\u0430\u043b\u044c\u043d\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#clean\" rel=\"noopener noreferrer nofollow\">\u0427\u0442\u043e \u0442\u0430\u043a\u043e\u0435 \u0447\u0438\u0441\u0442\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#advantages\" rel=\"noopener noreferrer nofollow\">\u041f\u043b\u044e\u0441\u044b \u0438 \u043c\u0438\u043d\u0443\u0441\u044b &#171;\u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043d\u043e\u0439&#187; \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438<\/a><\/p>\n<\/li>\n<\/ol>\n<h2>\u0421\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435 \u0441\u0442\u0430\u0442\u044c\u0438 (\u041f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u0447\u0430\u0441\u0442\u044c)<\/h2>\n<ol>\n<li>\n<p><a href=\"#development\" rel=\"noopener noreferrer nofollow\">\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#features\" rel=\"noopener noreferrer nofollow\">\u0420\u0430\u0437\u0431\u0438\u0432\u0430\u0435\u043c \u043f\u0440\u043e\u0435\u043a\u0442 \u043d\u0430 \u0444\u0438\u0447\u0438<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#data_work\" rel=\"noopener noreferrer nofollow\">\u0420\u0430\u0431\u043e\u0442\u0430 \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438: DataManagerFeatureApi<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#doctrineFeature\" rel=\"noopener noreferrer nofollow\">\u041c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0446\u0438\u044f \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438: DoctrineDataFeature (implements DataManagerFeatureApi)<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#category_feature\" rel=\"noopener noreferrer nofollow\">CategoryFeatureApi \u0438 CategoryFeature<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#post_feature\" rel=\"noopener noreferrer nofollow\">PostFeatureApi \u0438 PostFeature<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#front\" rel=\"noopener noreferrer nofollow\">FrontFeature<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/the_end\" rel=\"noopener noreferrer nofollow\">\u0418\u0442\u043e\u0433\u043e\u0432\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442<\/a><\/p>\n<\/li>\n<\/ol>\n<p>\u041f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u043c\u044b \u043d\u0430\u0447\u043d\u0451\u043c \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0442\u044c \u043a\u0430\u043a \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0431\u043b\u043e\u0433 \u043d\u0430 Symfony \u0441 DDD \u0438 Clean Architecture, \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u043c \u043e\u0441\u043d\u043e\u0432\u043d\u0443\u044e \u0442\u0435\u043e\u0440\u0438\u044e. \u0418 \u0442\u0430\u043a, \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c\u2026<\/p>\n<h2>\u0427\u0442\u043e \u0442\u0430\u043a\u043e\u0435 DDD (Domain Driven Design | Domain Driven Development)<\/h2>\n<p><a class=\"anchor\" name=\"ddd\" id=\"ddd\"><\/a><\/p>\n<p><strong>DDD (Domain Driven Design | Domain Driven Development)<\/strong> \u2013 \u044d\u0442\u043e <u>\u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043d\u044b\u0439<\/u> <u>\u043f\u043e\u0434\u0445\u043e\u0434<\/u>,  \u0437\u0430\u0434\u0430\u0447\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u2013 \u044d\u0442\u043e \u0432\u044b\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0431\u0438\u0437\u043d\u0435\u0441 \u043b\u043e\u0433\u0438\u043a\u0438 (Domain) \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u041e\u0442\u0441\u044e\u0434\u0430 \u0438 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u2013 Domain Driven. \u0417\u0434\u0435\u0441\u044c \u0442\u0430\u043a\u0436\u0435 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u044e\u0442\u0441\u044f \u0432\u043e \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043a\u043b\u0430\u0441\u0441\u043e\u0432, \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u044b, \u0445\u043e\u0440\u043e\u0448\u0438\u0435 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0438 \u0438 \u0442\u0434, \u043d\u043e \u044d\u0442\u043e \u0432\u0441\u0435 \u0432\u043d\u0443\u0442\u0440\u0438 \u0434\u043e\u043c\u0435\u043d\u043d\u043e\u0433\u043e \u0441\u043b\u043e\u044f. <\/p>\n<p>\u0414\u043e\u043c\u0435\u043d\u043d\u044b\u0439 \u0441\u043b\u043e\u0439 (Domain) \u043d\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c \u043e\u0442 \u0432\u043d\u0435\u0448\u043d\u0438\u0445 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a, Domain \u043d\u0435 \u043f\u0440\u0438\u0432\u044f\u0437\u0430\u043d \u043a \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445, \u043a \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u043e\u043c\u0443 \u0434\u0432\u0438\u0436\u043a\u0443 \u0438 \u043d\u0438\u043a\u043e\u0433\u0434\u0430 \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0437\u043d\u0430\u0435\u0442 \u043f\u0440\u043e \u0434\u0435\u0442\u0430\u043b\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0432\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043a\u0430\u043a\u0443\u044e \u0411\u0414 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c, \u0432\u0438\u0434 \u043a\u0435\u0448\u0430 \u0438 \u0442\u0434). \u0422\u0430\u043a\u0436\u0435 \u0434\u043e\u043c\u0435\u043d\u043d\u044b\u0439 \u0441\u043b\u043e\u0439 \u043d\u0435 \u043f\u0440\u0438\u0432\u044f\u0437\u0430\u043d \u043a \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0443, \u0435\u0441\u043b\u0438 \u0432\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0435, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, DDD \u043d\u0430 Symfony, \u0442\u043e \u0432 \u0438\u0434\u0435\u0430\u043b\u0435, \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0435\u043d\u043d\u044b\u0439 \u0434\u043e\u043c\u0435\u043d\u043d\u044b\u0439 \u0441\u043b\u043e\u0439 \u043d\u0430 Laravel (\u043b\u0438\u0431\u043e \u0434\u0440\u0443\u0433\u043e\u0439 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a), \u0434\u043e\u043b\u0436\u0435\u043d \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u0441\u0432\u043e\u044e \u0440\u0430\u0431\u043e\u0442\u043e\u0441\u043f\u043e\u0441\u043e\u0431\u043d\u043e\u0441\u0442\u044c.<\/p>\n<p>\u0418\u043d\u044b\u043c\u0438 \u0441\u043b\u043e\u0432\u0430\u043c\u0438, Domain \u2013 \u044d\u0442\u043e \u0441\u0435\u0440\u0434\u0446\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u0437\u0430\u0449\u0438\u0449\u0435\u043d\u043d\u043e\u0435 \u043e\u0442 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0438\u0437\u0432\u043d\u0435. \u0417\u0434\u0435\u0441\u044c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u044f\u0442 \u0441\u0430\u043c\u044b\u0435 \u0432\u0430\u0436\u043d\u044b\u0435 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u044b, \u043a\u0430\u0441\u0430\u0435\u043c\u044b\u0435 \u0431\u0438\u0437\u043d\u0435\u0441-\u043f\u0440\u0430\u0432\u0438\u043b, \u0442\u043e, \u0431\u0435\u0437 \u0447\u0435\u0433\u043e \u0431\u0438\u0437\u043d\u0435\u0441 \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c.<\/p>\n<p><strong>\u0421\u043e\u0432\u0441\u0435\u043c \u043a\u0440\u0430\u0442\u043a\u043e<\/strong>: <strong>Domain Driven Design | Domain Driven Development \u2013 <\/strong>\u044d\u0442\u043e \u0432\u044b\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0431\u0438\u0437\u043d\u0435\u0441 \u043b\u043e\u0433\u0438\u043a\u0438 \u0438 \u0435\u0433\u043e \u0438\u0437\u043e\u043b\u044f\u0446\u0438\u044f \u043e\u0442 \u0432\u043d\u0435\u0448\u043d\u0438\u0445 \u0444\u0430\u043a\u0442\u043e\u0440\u043e\u0432.<\/p>\n<h2>\u0427\u0442\u043e \u0442\u0430\u043a\u043e\u0435 \u0433\u0435\u043a\u0441\u0430\u0433\u043e\u043d\u0430\u043b\u044c\u043d\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 (Hexagonal architecture)<\/h2>\n<p><a class=\"anchor\" name=\"hexagonal\" id=\"hexagonal\"><\/a><\/p>\n<p><strong>\u0413\u0435\u043a\u0441\u0430\u0433\u043e\u043d\u0430\u043b\u044c\u043d\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430<\/strong> \u2013 \u044d\u0442\u043e <u>\u0432\u0438\u0434<\/u> <u>\u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b<\/u>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u0441\u043f\u043e\u0441\u043e\u0431 \u043e\u0431\u0449\u0435\u043d\u0438\u044f \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0434\u0440\u0443\u0433 \u0441 \u0434\u0440\u0443\u0433\u043e\u043c \u043f\u0443\u0442\u0435\u043c \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 \u0441\u043b\u043e\u0438 (layers), \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432 \u0441\u0432\u043e\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 \u0442\u0430\u043a \u043d\u0430\u0437\u044b\u0432\u0430\u0435\u043c\u044b\u0435 \u043f\u043e\u0440\u0442\u044b \u0434\u043b\u044f \u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0434\u0440\u0443\u0433 \u0441 \u0434\u0440\u0443\u0433\u043e\u043c.  <\/p>\n<p>\u0427\u0442\u043e \u0442\u0430\u043a\u043e\u0435 \u043f\u043e\u0440\u0442 \u0432 \u0433\u0435\u043a\u0441\u0430\u0433\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0435? \u0415\u0441\u043b\u0438 \u0433\u043e\u0432\u043e\u0440\u0438\u0442\u044c \u044f\u0437\u044b\u043a\u043e\u043c \u041e\u041e\u041f \u2013 \u044d\u0442\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441. \u041a\u0430\u0436\u0434\u044b\u0439 \u0441\u043b\u043e\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u043f\u043e\u0440\u0442-\u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0434\u0440\u0443\u0433\u043e\u0433\u043e \u0441\u043b\u043e\u044f, \u0430 \u043d\u0435 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u0443\u044e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e. <\/p>\n<p><strong>\u0427\u0442\u043e \u0436\u0435 \u0442\u0430\u043a\u043e\u0435 \u0441\u043b\u043e\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 (application\u2019s layers)? <\/strong> <\/p>\n<p>\u0418 \u0442\u0430\u043a, \u0441\u043b\u043e\u0439 \u2013 \u044d\u0442\u043e \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u043a\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u0433\u0434\u0435 \u043a\u0430\u0436\u0434\u0430\u044f \u0433\u0440\u0443\u043f\u043f\u0430 \u0438\u043c\u0435\u0435\u0442 \u0441\u0432\u043e\u0435 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0435 \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435. \u0412 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u043d\u0443\u0436\u0434 \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u043c\u043e\u0433\u0443\u0442 \u043f\u043e\u044f\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0441\u043b\u043e\u0438, \u043b\u0438\u0431\u043e \u0441\u043e\u043a\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0441\u043b\u043e\u0435\u0432.<\/p>\n<p>\u0421\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u0430\u0440\u0438\u0430\u0446\u0438\u0439, \u043d\u043e \u043d\u0430 \u043c\u043e\u0439 \u0432\u0437\u0433\u043b\u044f\u0434, \u0441\u0430\u043c\u044b\u043c \u043e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u043c \u0440\u0435\u0448\u0435\u043d\u0438\u0435\u043c \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0440\u0430\u0437\u0431\u0438\u0435\u043d\u0438\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0441\u043b\u043e\u0438:<\/p>\n<p><strong><u>Presentation Layer (\u0441\u043b\u043e\u0439 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f)<\/u> <\/strong>\u2013 \u0437\u0434\u0435\u0441\u044c \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432\u0441\u0435, \u0447\u0442\u043e \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 input\/output (\u0432\u0432\u043e\u0434\/\u0432\u044b\u0432\u043e\u0434), \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0448\u0430\u0431\u043b\u043e\u043d\u044b, \u043a\u043e\u043d\u0441\u043e\u043b\u044c\u043d\u044b\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u044b, \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u044b. \u0412\u0435\u0441\u044c input\/output \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0432 DTO Request (data transfer object) \u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442\u0441\u044f \u043d\u0430 \u0441\u043b\u043e\u0439 \u043d\u0438\u0436\u0435, \u0432 Application Layer. \u0422\u0430\u043a \u0436\u0435, \u0434\u0430\u043d\u043d\u044b\u0439 \u0441\u043b\u043e\u0439 \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442\u0441\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435\u043c DTO Response \u0438\u0437 Application Layer. \u0417\u0434\u0435\u0441\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0432\u0432\u043e\u0434 \u0438 \u0432\u044b\u0432\u043e\u0434, \u043d\u0438\u043a\u0430\u043a\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0439 \u0441\u043b\u043e\u0439 \u0432 \u0441\u0435\u0431\u0435 \u043d\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442.  <\/p>\n<p><strong><u>Application<\/u><\/strong><u> <\/u><strong><u>Layer (\u0441\u043b\u043e\u0439 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f)<\/u> <\/strong>\u2013 \u043f\u0440\u043e\u0441\u043b\u043e\u0439\u043a\u0430 \u043c\u0435\u0436\u0434\u0443 Domain \u0438 Presentation, \u0437\u0434\u0435\u0441\u044c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438e DTO Request \u0438\u0437 input\/output (Presentaion Layer), \u043f\u0435\u0440\u0432\u0438\u0447\u043d\u0430\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \/ \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044f \u0432\u0432\u043e\u0434\u0430, \u043c\u0430\u043f\u043f\u0438\u043d\u0433 DTO \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0432 Domain Layer \u0438 \u043d\u0430\u043e\u0431\u043e\u0440\u043e\u0442, \u0432\u044b\u0437\u043e\u0432 \u0431\u0438\u0437\u043d\u0435\u0441 \u043b\u043e\u0433\u0438\u043a\u0438 \u0438\u0437 Domain Layer.  <\/p>\n<p>\u0418\u043d\u044b\u043c\u0438 \u0441\u043b\u043e\u0432\u0430\u043c\u0438, \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u0440\u0435\u043a\u0432\u0435\u0441\u0442, \u043f\u0440\u043e\u0438\u0437\u0432\u0435\u043b\u0438 \u043c\u0430\u043f\u043f\u0438\u043d\u0433 \u0432 Domain Entity, \u0432\u044b\u0437\u0432\u0430\u043b\u0438 \u0438\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u043e\u0440 \/ usecase, \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043e\u0442 Domain Layer, \u0441\u0434\u0435\u043b\u0430\u043b\u0438 \u043c\u0430\u043f\u0438\u043d\u0433 \u0432 DTO Response \u0438 \u0432\u0435\u0440\u043d\u0443\u043b\u0438 \u043d\u0430 \u0441\u043b\u043e\u0439 Presentation, \u0433\u0434\u0435 \u0443\u0436\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043a\u0430\u0437\u0430\u043d \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e (\u0435\u0441\u043b\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e)<\/p>\n<p><strong><u>Domain<\/u><\/strong><u> <\/u><strong><u>Layer (\u0434\u043e\u043c\u0435\u043d\u043d\u044b\u0439 \u0441\u043b\u043e\u0439)<\/u> <\/strong>\u2013 \u0441\u043b\u043e\u0439 \u0441 \u0431\u0438\u0437\u043d\u0435\u0441 \u043b\u043e\u0433\u0438\u043a\u043e\u0439. \u0427\u0443\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u043c \u0432  \u0440\u0430\u0437\u0434\u0435\u043b\u0435 <strong>Clean<\/strong> <strong>Architecture. <\/strong>\u0412\u0410\u0416\u041d\u041e: \u0412 \u0438\u0434\u0435\u0430\u043b\u0435, \u0434\u043e\u043c\u0435\u043d\u043d\u044b\u0439 \u0441\u043b\u043e\u0439 \u043d\u0435 \u0437\u043d\u0430\u0435\u0442 \u043f\u0440\u043e \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u043d\u0438\u0435 \u0434\u0440\u0443\u0433\u0438\u0445 \u0441\u043b\u043e\u0435\u0432.<\/p>\n<p><strong><u>Infrastructure<\/u><\/strong> \u2013 \u0441\u043b\u043e\u0439, \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u0439 \u0441\u043e \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u043c\u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430\u043c\u0438, \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430\u043c\u0438 \u0438 \u0442\u0434.<\/p>\n<p>           \u041d\u0430\u0433\u043b\u044f\u0434\u043d\u043e \u0441\u0445\u0435\u043c\u0443 \u0441\u043b\u043e\u0435\u0432 \u0432 \u0433\u0435\u043a\u0441\u0430\u0433\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0435 \u043c\u043e\u0436\u043d\u043e \u0438\u0437\u043e\u0431\u0440\u0430\u0437\u0438\u0442\u044c \u0442\u0430\u043a:<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u0412\u0430\u0436\u043d\u043e \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e \u043a\u0430\u0436\u0434\u044b\u0439 \u0441\u043b\u043e\u0439 \u0438\u043c\u0435\u0435\u0442 \u0441\u0432\u043e\u0438 \u043c\u0430\u043f\u043f\u0435\u0440\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u044e\u0442 \u043e\u0431\u044a\u0435\u043a\u0442 \u0438\u0437 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0441\u043b\u043e\u044f \u0432 \u043e\u0431\u044a\u0435\u043a\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0441\u043b\u043e\u044f. \u0411\u043e\u043b\u0435\u0435 \u0434\u0435\u0442\u0430\u043b\u044c\u043d\u043e \u043c\u044b \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u043c \u044d\u0442\u043e \u043d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435.<\/p>\n<h2>\u0427\u0442\u043e \u0442\u0430\u043a\u043e\u0435 \u0447\u0438\u0441\u0442\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 (Clean  Architecture)<\/h2>\n<p><a class=\"anchor\" name=\"clean\" id=\"clean\"><\/a><\/p>\n<p><strong>Clean<\/strong>  <strong>Architecture \u2013 <\/strong>\u0431\u044b\u043b\u0430 \u043e\u043f\u0438\u0441\u0430\u043d\u0430 \u0420\u043e\u0431\u0435\u0440\u0442\u043e\u043c \u041c\u0430\u0440\u0442\u0438\u043d\u043e\u043c (\u00ab\u0414\u044f\u0434\u044e\u0448\u043a\u043e\u0439 \u0411\u043e\u0431\u043e\u043c\u00bb) &#8212; \u043e\u0447\u0435\u043d\u044c \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e \u0435\u0433\u043e \u043a\u043d\u0438\u0433\u0438 \u043a \u043f\u0440\u043e\u0447\u0442\u0435\u043d\u0438\u044e. \u0414\u0430\u043d\u043d\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u043e\u0441\u043d\u043e\u0432\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043d\u0430 \u0433\u0435\u043a\u0441\u0430\u0433\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0435, \u043e\u0434\u043d\u0430\u043a\u043e \u0441 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u043c\u0438 \u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f\u043c\u0438. \u0417\u0434\u0435\u0441\u044c \u0432\u0432\u043e\u0434\u044f\u0442\u0441\u044f \u0442\u0430\u043a\u0438\u0435 \u043f\u043e\u043d\u044f\u0442\u0438\u044f, \u043a\u0430\u043a: Use Case, Interactor, Entity.<\/p>\n<p><strong>\u0427\u0442\u043e \u0436\u0435 \u0442\u0430\u043a\u043e\u0435 Domain Entity \u043f\u0440\u043e\u0441\u0442\u044b\u043c\u0438 \u0441\u043b\u043e\u0432\u0430\u043c\u0438?<\/strong> \u042d\u0442\u043e \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438, \u0431\u0435\u0437 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0431\u0438\u0437\u043d\u0435\u0441 \u043f\u0440\u043e\u0441\u0442\u043e \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u043c \u0431\u0430\u043d\u043a, \u0438 \u043e\u0442\u0431\u0440\u043e\u0441\u0438\u043c \u0432\u0441\u0435 \u0434\u0435\u0442\u0430\u043b\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438. \u0427\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u044f\u0432\u043b\u044f\u0442\u044c\u0441\u044f domain entity \u0434\u043b\u044f \u0431\u0430\u043d\u043a\u0430? \u042d\u0442\u043e \u043d\u0430\u0432\u0435\u0440\u043d\u044f\u043a\u0430 \u0431\u0443\u0434\u0435\u0442 UserEntity, AccountEntity \u0438 \u0442\u0434.<\/p>\n<p><strong>\u0427\u0442\u043e \u0436\u0435 \u0442\u0430\u043a\u043e\u0435 Use Case \u043f\u0440\u043e\u0441\u0442\u044b\u043c\u0438 \u0441\u043b\u043e\u0432\u0430\u043c\u0438?<\/strong> \u041f\u043e \u0441\u0443\u0442\u0438, \u044d\u0442\u043e \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u044b, \u0431\u0435\u0437 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0431\u0438\u0437\u043d\u0435\u0441. \u041d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0431\u0430\u043d\u043a\u0430, Use Case \u0431\u0443\u0434\u0435\u0442 \u044f\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u043e\u0442\u043a\u0440\u044b\u0442\u0438\u0435 \u0441\u0447\u0435\u0442\u0430, \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0432\u043a\u043b\u0430\u0434\u0430, \u0437\u0430\u043a\u0440\u044b\u0442\u0438\u0435 \u0441\u0447\u0435\u0442\u0430, \u0437\u0430\u043a\u0430\u0437 \u043a\u0430\u0440\u0442\u044b \u0438 \u0442\u0434.<\/p>\n<p><strong>\u0427\u0442\u043e \u0436\u0435 \u0442\u043e\u0433\u0434\u0430 Intercator \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442?<\/strong> \u042d\u0442\u043e \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c, \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u044e\u0449\u0438\u0439 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e Use Case. \u0413\u043e\u0432\u043e\u0440\u044f \u043d\u0430 \u044f\u0437\u044b\u043a\u0435 \u041e\u041e\u041f \u2013 \u044d\u0442\u043e \u043a\u043b\u0430\u0441\u0441, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043e\u043f\u0438\u0441\u0430\u043d\u044b \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e Use Case. \u041a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u044d\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043a\u043e\u0434 \u0431\u043e\u043b\u0435\u0435 \u043a\u043e\u043c\u043f\u0430\u043a\u0442\u043d\u044b\u043c.<\/p>\n<p>\u042f \u0441\u0442\u0430\u0440\u0430\u044e\u0441\u044c \u043f\u0440\u0438\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c\u0441\u044f \u0447\u0438\u0441\u0442\u043e\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b, \u043e\u043d\u0430 \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0432 \u0441\u0435\u0431\u044f \u0432\u0441\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0435, \u0447\u0442\u043e \u043d\u0443\u0436\u043d\u043e \u0434\u043b\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0441 \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u0443\u0435\u043c\u044b\u043c \u043a\u043e\u0434\u043e\u043c.<\/p>\n<p><strong>\u041f\u043b\u044e\u0441\u044b \u0438 \u043c\u0438\u043d\u0443\u0441\u044b \u0447\u0438\u0441\u0442\u043e\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b :<\/strong><\/p>\n<p><a class=\"anchor\" name=\"advantages\" id=\"advantages\"><\/a><\/p>\n<p>\u0423 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0430 \u0435\u0441\u0442\u044c \u043f\u043e\u043b\u043e\u0436\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0438 \u043e\u0442\u0440\u0438\u0446\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0441\u0442\u043e\u0440\u043e\u043d\u044b. \u041c\u043e\u0436\u043d\u043e \u0431\u0435\u0441\u043a\u043e\u043d\u0435\u0447\u043d\u043e \u0434\u043e\u043b\u0433\u043e \u0440\u0430\u0441\u0441\u0443\u0436\u0434\u0430\u0442\u044c \u043d\u0430 \u0442\u0435\u043c\u0443 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043d\u044b\u0445 \u043f\u043e\u0434\u0445\u043e\u0434\u043e\u0432, \u0438 \u0432\u044b\u0434\u0435\u043b\u0438\u0442\u044c \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u201c\u0437\u0430\u201d \u0438 \u201c\u043f\u0440\u043e\u0442\u0438\u0432\u201d, \u043e\u0434\u043d\u0430\u043a\u043e \u0437\u0434\u0435\u0441\u044c \u044f \u043f\u0440\u0438\u0432\u0435\u0434\u0443 \u0441\u0430\u043c\u044b\u0435 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043f\u0443\u043d\u043a\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435, \u043d\u0430 \u043c\u043e\u0439 \u0432\u0437\u0433\u043b\u044f\u0434, \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0441\u0430\u043c\u044b\u043c\u0438 \u0432\u0430\u0436\u043d\u044b\u043c\u0438.<\/p>\n<p><strong>\u041d\u0430\u0447\u043d\u0435\u043c \u0441 \u043c\u0438\u043d\u0443\u0441\u043e\u0432:<\/strong><\/p>\n<p><strong>&#8212; \u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0441 \u043a\u0430\u0434\u0440\u0430\u043c\u0438 <\/strong>\u2013 \u0434\u0430\u043b\u0435\u043a\u043e \u043d\u0435 \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0437\u043d\u0430\u0435\u0442 \u043f\u0440\u043e \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 \u0441\u043b\u043e\u0438, \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0443, \u0434\u0430 \u0438 \u0432 \u0446\u0435\u043b\u043e\u043c, \u0434\u043b\u044f \u0447\u0435\u0433\u043e \u044d\u0442\u043e \u043d\u0443\u0436\u043d\u043e. \u041e\u0442\u0441\u044e\u0434\u0430 \u0432\u044b\u0442\u0435\u043a\u0430\u0435\u0442 \u043f\u0443\u043d\u043a\u0442 \u043d\u0438\u0436\u0435<\/p>\n<p>&#8212;<strong> \u0414\u043e\u0440\u043e\u0433\u043e\u0432\u0438\u0437\u043d\u0430 \u0432 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 &#8212;<\/strong> \u0434\u0430\u043d\u043d\u044b\u0439 \u043f\u0443\u043d\u043a\u0442 \u043c\u043e\u0436\u043d\u043e \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u044c \u043d\u0430 2 \u043c\u043e\u043c\u0435\u043d\u0442\u0430. \u0412\u043e-\u043f\u0435\u0440\u0432\u044b\u0445, \u0442\u0430\u043a\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043a\u0430\u043a \u043c\u0438\u043d\u0438\u043c\u0443\u043c \u0433\u0440\u0430\u043c\u043e\u0442\u043d\u043e\u0433\u043e \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u043e\u0440\u0430, \u043b\u0438\u0431\u043e \u0441\u0435\u043d\u044c\u0435\u0440\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u0438\u043c\u0435\u0435\u0442 \u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0440\u0435\u0439\u0442 \u0437\u0430 \u0447\u0430\u0441. \u0412\u043e-\u0432\u0442\u043e\u0440\u044b\u0445, \u043d\u0430 \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u0435 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0437\u0430\u0434\u0430\u0447 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0431\u043e\u043b\u044c\u0448\u0435 \u0432\u0440\u0435\u043c\u0435\u043d\u0438, \u0442\u043a \u0432\u044b\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0434\u043e\u043c\u0435\u043d\u043d\u043e\u0433\u043e \u0441\u043b\u043e\u044f \u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u044d\u043a\u043e\u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0434\u043b\u044f \u043a\u043e\u043c\u043c\u0443\u043d\u0438\u043a\u0430\u0446\u0438\u0438 \u0441 \u0434\u043e\u043c\u0435\u043d\u043e\u043c \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0431\u041e\u043b\u044c\u0448\u0435\u0433\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u043a\u043e\u0434\u0430 (\u043d\u0430 \u043f\u0435\u0440\u0432\u044b\u0445 \u044d\u0442\u0430\u043f\u0430\u0445).<\/p>\n<p><strong>&#8212; \u041c\u043d\u043e\u0433\u043e \u043e\u0434\u043d\u043e\u0442\u0438\u043f\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430 (\u043d\u0435 \u043f\u0443\u0442\u0430\u0442\u044c \u0441 \u043a\u043e\u043f\u0438\u043f\u0430\u0441\u0442\u043e\u0439!)<\/strong> &#8212; \u043f\u0440\u0438\u0433\u043e\u0442\u043e\u0432\u044c\u0442\u0435\u0441\u044c \u043f\u0438\u0441\u0430\u0442\u044c \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u043a\u043e\u0434\u0430, \u0434\u0430 \u0438 \u0435\u0449\u0435 \u0441\u0445\u043e\u0436\u0435\u0433\u043e \u0434\u0440\u0443\u0433 \u0441 \u0434\u0440\u0443\u0433\u043e\u043c \u043e\u0442 \u0444\u0438\u0447\u0438 \u043a \u0444\u0438\u0447\u0435 (\u0438 \u043e\u0442 \u0441\u043b\u043e\u044f \u043a \u0441\u043b\u043e\u044e). \u0414\u0430, api, \u0432\u0435\u0447\u043d\u044b\u0435 \u043c\u0430\u043f\u043f\u0438\u043d\u0433\u0438 \u0438 \u0442\u0434 \u0438\u043d\u043e\u0433\u0434\u0430 \u043e\u0447\u0435\u043d\u044c \u0441\u0438\u043b\u044c\u043d\u043e \u043d\u0435\u0440\u0432\u0438\u0440\u0443\u044e\u0442.<\/p>\n<p><strong>&#8212; \u041f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u044b\u0439 \u0441\u0430\u043c\u043e\u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044c \u2013 <\/strong>\u0435\u0441\u043b\u0438 \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 \u044f\u0437\u044b\u043a\u0430 \u043d\u0435 \u043f\u0440\u0435\u0434\u0443\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043a\u043e\u0434\u0430 \u043d\u0430 \u043f\u0430\u043a\u0435\u0442\u044b (\u043a\u0430\u043a \u0432 Java), \u043d\u0443\u0436\u043d\u043e \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e \u0441\u0435\u0431\u044f \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043a\u043b\u0430\u0441\u0441\u044b\/\u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u044b \u0438\u0437 \u0434\u0440\u0443\u0433\u0438\u0445 \u0441\u043b\u043e\u0435\u0432\/\u0444\u0438\u0447, \u043c\u0438\u043d\u0443\u044f api.  <\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u043e\u0433\u043e\u0432\u043e\u0440\u0438\u043c \u043e <strong>\u043f\u043b\u044e\u0441\u0430\u0445 \u0447\u0438\u0441\u0442\u043e\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b<\/strong>:<\/p>\n<p><strong>&#8212; \u0421\u043b\u0430\u0431\u0430\u044f \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c \u043a\u043e\u0434\u0430 \u2013 <\/strong>\u0442\u043a \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u043e \u043d\u0430 \u0441\u043b\u043e\u0438, \u0433\u0434\u0435 \u043a\u0430\u0436\u0434\u044b\u0439 \u0441\u043b\u043e\u0439 \u0438\u0437\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u043d \u0434\u0440\u0443\u0433 \u043e\u0442 \u0434\u0440\u0443\u0433\u0430, \u0442\u043e \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0432 \u043e\u0434\u043d\u043e\u043c \u0441\u043b\u043e\u0435 \u043d\u0435 \u0432\u043b\u0438\u044f\u0435\u0442 \u043d\u0430 \u0434\u0440\u0443\u0433\u043e\u0439.<\/p>\n<p><strong>&#8212; \u041b\u0435\u0433\u043a\u043e \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u2013 <\/strong>\u0442\u043a \u0441\u043b\u043e\u0438 \u043d\u0435 \u0437\u0430\u0432\u0438\u0441\u044f\u0442 \u0434\u0440\u0443\u0433 \u043e\u0442 \u0434\u0440\u0443\u0433\u0430, \u0442\u043e \u043f\u0440\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u0431\u0438\u0437\u043d\u0435\u0441 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0432, \u043f\u0440\u043e\u0435\u043a\u0442 \u043c\u043e\u0436\u043d\u043e \u043b\u0435\u0433\u043a\u043e \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u043b\u0438\u0431\u043e \u0436\u0435 \u043d\u0430\u043e\u0431\u043e\u0440\u043e\u0442 \u2013 \u0443\u0431\u0440\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435 \u043d\u0443\u0436\u0435\u043d.<\/p>\n<p><strong>&#8212; \u041b\u0435\u0433\u043a\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u2013 <\/strong>\u0434\u0430\u043d\u043d\u044b\u0439 \u043a\u043e\u0434 \u0445\u043e\u0440\u043e\u0448\u043e \u043f\u043e\u0434\u0434\u0430\u0435\u0442\u0441\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e. \u0417\u0430 \u0441\u0447\u0435\u0442 \u0438\u0437\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u043a\u043e\u0434\u0430 \u043f\u043e \u0441\u043b\u043e\u044f\u043c, \u043f\u0440\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u043a\u043e\u0434\u0430 \u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0442\u0435\u0441\u0442\u043e\u0432.<\/p>\n<p><strong>&#8212; \u0414\u0435\u0448\u0435\u0432\u043e \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c<\/strong> \u2013 \u0434\u0430, \u0440\u0430\u0437\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u0434\u0443\u043a\u0442 \u0441 \u0442\u0430\u043a\u0438\u043c \u043f\u043e\u0434\u0445\u043e\u0434\u043e\u043c \u0434\u043e\u0440\u043e\u0433\u043e, \u043e\u0434\u043d\u0430\u043a\u043e, \u0435\u0441\u043b\u0438 \u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043d\u0430\u043f\u0435\u0440\u0441\u043f\u0435\u043a\u0442\u0438\u0432\u0443, \u0442\u043e \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0431\u0443\u0434\u0435\u0442 \u0434\u0435\u0448\u0435\u0432\u043b\u0435. \u0427\u0435\u0433\u043e \u043d\u0435\u043b\u044c\u0437\u044f \u0441\u043a\u0430\u0437\u0430\u0442\u044c \u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435 \u043f\u0440\u0438\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043d\u044b\u0445 \u043f\u043e\u0434\u0445\u043e\u0434\u043e\u0432.  <\/p>\n<p><strong>\u041a\u043e\u0433\u0434\u0430 \u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0447\u0438\u0441\u0442\u0443\u044e \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0443?<\/strong><\/p>\n<p>\u0427\u0438\u0441\u0442\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u2013 \u044d\u0442\u043e \u043e\u0447\u0435\u043d\u044c \u043c\u043e\u0449\u043d\u044b\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0435\u043c\u043e\u0433\u043e \u0438 \u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u042d\u0442\u043e \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u0435\u043e\u0440\u0438\u044f \/ \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f, \u043d\u043e \u0442\u0430\u043a \u0436\u0435 \u0438 \u043e\u0431\u0440\u0430\u0437 \u043c\u044b\u0448\u043b\u0435\u043d\u0438\u044f. \u041a\u043e\u0433\u0434\u0430 \u0436\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0447\u0438\u0441\u0442\u043e\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u043e\u043f\u0440\u0430\u0432\u0434\u044b\u0432\u0430\u0442\u044c \u0441\u0435\u0431\u044f? \u042f \u0431\u044b \u0441\u043a\u0430\u0437\u0430\u043b\u0430, \u0447\u0442\u043e \u043e\u043d\u0430 \u0432\u0441\u0435\u0433\u0434\u0430 \u0441\u0435\u0431\u044f \u043e\u043f\u0440\u0430\u0432\u0434\u044b\u0432\u0430\u0435\u0442. \u0412\u0435\u0434\u044c \u0445\u043e\u0440\u043e\u0448\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0435\u0449\u0435 \u043d\u0438\u043a\u043e\u0433\u0434\u0430 \u043d\u0435 \u0432\u044b\u0437\u044b\u0432\u0430\u043b\u043e \u043d\u0435\u0433\u0430\u0442\u0438\u0432\u043d\u043e\u0439  \u0440\u0435\u0430\u043a\u0446\u0438\u0438! \u041e\u0434\u043d\u0430\u043a\u043e \u043d\u0435 \u0441\u0442\u043e\u0438\u0442 \u0437\u0430\u0431\u044b\u0432\u0430\u0442\u044c \u043f\u0440\u043e \u043a\u043e\u043c\u043c\u0435\u0440\u0446\u0438\u044e \u0438 \u0431\u0438\u0437\u043d\u0435\u0441. \u041d\u0435 \u0432\u0441\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u044b, \u0443 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u044b \u0441 \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u043c \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u044b\u043c \u0446\u0438\u043a\u043b\u043e\u043c, \u0433\u043e\u0442\u043e\u0432\u044b \u043f\u043b\u0430\u0442\u0438\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u0435 \u0437\u0430 \u0445\u043e\u0440\u043e\u0448\u0443\u044e \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0443. \u041d\u043e \u044d\u0442\u043e \u043d\u0435 \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043e \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u044b \u043d\u0435 \u0437\u0430\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u044e\u0442 \u0445\u043e\u0440\u043e\u0448\u0435\u0433\u043e \u043a\u043e\u0434\u0430! =)<\/p>\n<p>\u0418 \u0442\u0430\u043a, \u0442\u0435\u043f\u0435\u0440\u044c \u043a \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435:<\/p>\n<h2>\u041f\u0440\u0430\u043a\u0442\u0438\u043a\u0430: \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0431\u043b\u043e\u0433\u0430 \u043d\u0430 Symfony \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0447\u0438\u0441\u0442\u043e\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b (Clean Architecture)<\/h2>\n<p><a class=\"anchor\" name=\"development\" id=\"development\"><\/a><\/p>\n<p>\u0412\u044b\u0448\u0435 \u044f \u043f\u0438\u0441\u0430\u043b\u0430 \u043f\u0440\u043e \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 \u0441\u043b\u043e\u0438. \u041e\u0434\u043d\u0430\u043a\u043e \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0447\u0430\u0441\u0442\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0440\u0430\u0437\u0431\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430 \u0441\u043b\u043e\u0438, \u043d\u043e \u0438 \u043d\u0430 \u0444\u0438\u0447\u0438. \u041a\u0430\u0436\u0434\u0430\u044f \u0444\u0438\u0447\u0430 \u0438\u043c\u0435\u0435\u0442 \u0442\u0430\u043a\u043e\u0439 \u0436\u0435 \u043d\u0430\u0431\u043e\u0440 \u0441\u043b\u043e\u0435\u0432, \u0447\u0442\u043e \u0431\u044b\u043b\u0438 \u043e\u043f\u0438\u0441\u0430\u043d\u044b \u0432\u044b\u0448\u0435. (\u0434\u043e\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435\/\u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0445 \u0441\u043b\u043e\u0435\u0432 \u0432 \u0444\u0438\u0447\u0430\u0445). \u041c\u043d\u0435 \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0440\u0430\u0432\u0438\u0442\u0441\u044f \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043f\u043e \u0444\u0438\u0447\u0430\u043c.<\/p>\n<p>\u0418 \u0442\u0430\u043a, \u043a\u0430\u043a\u043e\u0439 \u043f\u043b\u0430\u043d? \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0431\u043b\u043e\u0433, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u043f\u043e\u0441\u0442\u043e\u0432 \u0438 \u0432\u044b\u0432\u043e\u0434 \u0438\u0445 \u0432 \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0438.<\/p>\n<p>\u041f\u0440\u0435\u0436\u0434\u0435, \u0447\u0435\u043c \u043d\u0430\u0447\u043d\u0435\u043c, \u0441\u043a\u0430\u0436\u0443 \u0441\u0440\u0430\u0437\u0443 \u2013 \u044f \u043d\u0435 \u0441\u0438\u043c\u0444\u043e\u043d\u0438 \u0434\u0435\u0432\u0435\u043b\u043e\u043f\u0435\u0440, \u043c\u043d\u0435 \u043d\u0440\u0430\u0432\u0438\u0442\u0441\u044f \u044d\u0442\u043e\u0442 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0438 \u043e\u0431\u043a\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u0441\u0432\u043e\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u044b\/\u0438\u0434\u0435\u0438. \u042f \u0437\u043d\u0430\u044e, \u0447\u0442\u043e \u0443 \u0441\u0438\u043c\u0444\u043e\u043d\u0438 \u0435\u0441\u0442\u044c \u0441\u0432\u043e\u0439 best practice , \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043e\u043f\u0438\u0441\u0430\u043d\u044b \u201c\u043f\u0430\u043f\u043e\u0447\u043a\u0438\u201d \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0438 \u0447\u0442\u043e \u0442\u0430\u043c \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c. \u041d\u043e \u043f\u0430\u043f\u043e\u0447\u043a\u0438 \u2013 \u044d\u0442\u043e \u043d\u0435 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430, \u043d\u0435 \u0442\u0430\u043a \u043b\u0438? \u0410 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u0442 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043b\u0435\u0433\u043a\u0443\u044e \u043a\u0430\u0441\u0442\u043e\u043c\u0438\u0437\u0430\u0446\u0438\u044e \u201c\u043f\u0430\u043f\u043e\u0447\u0435\u043a\u201d \u043f\u043e\u0434 \u0441\u0432\u043e\u0438 \u043d\u0443\u0436\u0434\u044b. \u0418 \u0432\u043e\u043e\u0431\u0449\u0435, \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u2013 \u044d\u0442\u043e \u0432\u0441\u0435\u0433\u043e \u043b\u0438\u0448\u044c \u0434\u0435\u0442\u0430\u043b\u044c \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438.<\/p>\n<p>\u0415\u0441\u043b\u0438 \u043a\u043e\u043c\u0443-\u0442\u043e \u043f\u0440\u043e\u0449\u0435 \u0441\u0440\u0430\u0437\u0443 \u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438, \u0442\u043e \u043e\u0441\u0442\u0430\u0432\u043b\u044e \u0435\u0449\u0435 \u0440\u0430\u0437 \u0442\u0443\u0442 \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 &#8212; <a href=\"https:\/\/github.com\/annysmolyan\/symfony-ddd-clean-architecture-blog\" rel=\"noopener noreferrer nofollow\">\u043f\u0440\u044f\u043c\u0430\u044f \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0433\u0438\u0442\u0445\u0430\u0431<\/a><\/p>\n<p>\u0418 \u0442\u0430\u043a, \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c.<\/p>\n<h3>\u0420\u0430\u0437\u0431\u0438\u0432\u0430\u0435\u043c \u043d\u0430 \u0444\u0438\u0447\u0438<\/h3>\n<p><a class=\"anchor\" name=\"features\" id=\"features\"><\/a><\/p>\n<p>\u041a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e \u043b\u044e\u0434\u0435\u0439, \u043f\u0440\u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u041f\u041e, \u0432 \u043f\u0435\u0440\u0432\u0443\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u043e\u043f\u0438\u0440\u0430\u044e\u0442\u0441\u044f \u043d\u0430 \u0433\u0440\u0430\u0444\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0434\u0438\u0437\u0430\u0439\u043d, \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0441\u0442\u0440\u043e\u044f\u0442\u0441\u044f \u043c\u043e\u0434\u0435\u043b\u0438(\u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438) \u0438<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-345857","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/345857","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=345857"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/345857\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=345857"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=345857"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=345857"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}