{"id":322802,"date":"2021-05-09T15:00:13","date_gmt":"2021-05-09T15:00:13","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=322802"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=322802","title":{"rendered":"\u041c\u043e\u0434\u0443\u043b\u044c\u043d\u044b\u0435 front-end \u0431\u043b\u043e\u043a\u0438 \u2013 \u043f\u0438\u0448\u0435\u043c \u0441\u0432\u043e\u0439 \u043c\u0438\u043d\u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a"},"content":{"rendered":"\n<div class=\"post__text post__text_v2\" id=\"post-content-body\">\n<p>\u0414\u043e\u0431\u0440\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0441\u0443\u0442\u043e\u043a \u0443\u0432\u0430\u0436\u0430\u0435\u043c\u044b\u0435 \u0447\u0438\u0442\u0430\u0442\u0435\u043b\u0438 \u0445\u0430\u0431\u0440\u0430. \u0421 \u043a\u0430\u0436\u0434\u044b\u043c \u0433\u043e\u0434\u043e\u043c \u0432 \u0432\u0435\u0431 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u043f\u043e\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432\u0441\u0435 \u0431\u043e\u043b\u044c\u0448\u0435 \u0440\u0430\u0437\u043d\u043e\u043e\u0431\u0440\u0430\u0437\u043d\u044b\u0445 \u0440\u0435\u0448\u0435\u043d\u0438\u0439 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 \u043c\u043e\u0434\u0443\u043b\u044c\u043d\u044b\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u0438 \u0443\u043f\u0440\u043e\u0449\u0430\u044e\u0442 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0438 \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043a\u043e\u0434\u0430. \u0412 \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u0432\u0430\u043c \u0441\u0432\u043e\u0439 \u0432\u0437\u0433\u043b\u044f\u0434 \u043d\u0430 \u0442\u043e, \u043a\u0430\u043a\u0438\u043c\u0438 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0435 front-end \u0431\u043b\u043e\u043a\u0438 (\u0434\u043b\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432 \u0441 \u0431\u044d\u043a\u0435\u043d\u0434\u043e\u043c \u043d\u0430 php) \u0438 \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u043f\u0440\u043e\u0439\u0442\u0438 \u0432\u0441\u0435 \u0448\u0430\u0433\u0438 \u043e\u0442 \u0438\u0434\u0435\u0438 \u0434\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0432\u043c\u0435\u0441\u0442\u0435 \u0441\u043e \u043c\u043d\u043e\u0439. \u0417\u0432\u0443\u0447\u0438\u0442 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e? \u0422\u043e\u0433\u0434\u0430 \u0434\u043e\u0431\u0440\u043e \u043f\u043e\u0436\u0430\u043b\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0434 \u043a\u0430\u0442.<\/p>\n<h2>\u041f\u0440\u0435\u0434\u0438\u0441\u043b\u043e\u0432\u0438\u0435<\/h2>\n<p>\u041f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044e\u0441\u044c &#8212; \u044f \u043c\u043e\u043b\u043e\u0434\u043e\u0439 \u0432\u0435\u0431 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0441 \u043e\u043f\u044b\u0442\u043e\u043c \u0440\u0430\u0431\u043e\u0442\u044b 5 \u043b\u0435\u0442.  \u041a\u0440\u0430\u0439\u043d\u0438\u0439 \u0433\u043e\u0434 \u044f \u0440\u0430\u0431\u043e\u0442\u0430\u044e \u043d\u0430 \u0444\u0440\u0438\u043b\u0430\u043d\u0441\u0435 \u0438 \u0431\u043e\u043b\u044c\u0448\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u0442\u0435\u043a\u0443\u0449\u0438\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432 \u0441\u0432\u044f\u0437\u0430\u043d\u0430 \u0441 WordPress. \u041d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u0440\u0430\u0437\u043b\u0438\u0447\u0443\u044e \u043a\u0440\u0438\u0442\u0438\u043a\u0443 CMS \u0432 \u043e\u0431\u0449\u0435\u043c \u0438 WordPress \u0432 \u0447\u0430\u0441\u043d\u043e\u0441\u0442\u0438, \u044f \u0441\u0447\u0438\u0442\u0430\u044e \u0441\u0430\u043c\u0430 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 WordPress \u044d\u0442\u043e \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0443\u0434\u0430\u0447\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435, \u0445\u043e\u0442\u044f \u043a\u043e\u043d\u0435\u0447\u043d\u043e \u043d\u0435 \u0431\u0435\u0437 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0445 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043a\u043e\u0432. \u0418 \u043e\u0434\u0438\u043d \u0438\u0437 \u043d\u0438\u0445 \u043d\u0430 \u043c\u043e\u0439 \u0432\u0437\u0433\u043b\u044f\u0434 \u044d\u0442\u043e \u0448\u0430\u0431\u043b\u043e\u043d\u044b. \u0412 \u043a\u0440\u0430\u0439\u043d\u0438\u0445 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f\u0445 \u0441\u0434\u0435\u043b\u0430\u043d\u044b \u0431\u043e\u043b\u044c\u0448\u0438\u0435 \u0448\u0430\u0433\u0438 \u0447\u0442\u043e\u0431\u044b \u044d\u0442\u043e \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u0442\u044c, \u0438 Gutenberg \u0432 \u0446\u0435\u043b\u043e\u043c \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u043c\u043e\u0449\u043d\u044b\u043c \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u043c, \u043e\u0434\u043d\u0430\u043a\u043e \u043a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e \u0432 \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u0435 \u0442\u0435\u043c \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0435\u0442\u0441\u044f \u043a\u0430\u0448\u0430 \u0432 \u0448\u0430\u0431\u043b\u043e\u043d\u0430\u0445, \u0441\u0442\u0438\u043b\u044f\u0445 \u0438 \u0441\u043a\u0440\u0438\u043f\u0442\u0430\u0445, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0434\u0435\u043b\u0430\u0435\u0442 \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0447\u0435\u0433\u043e-\u043b\u0438\u0431\u043e \u043a\u0440\u0430\u0439\u043d\u0435 \u0431\u043e\u043b\u0435\u0437\u043d\u0435\u043d\u043d\u044b\u043c, \u0430 \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043a\u043e\u0434\u0430 \u0437\u0430\u0447\u0430\u0441\u0442\u0443\u044e \u043d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u043c. \u0418\u043c\u0435\u043d\u043d\u043e \u044d\u0442\u0430 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0438 \u043f\u043e\u0434\u0442\u043e\u043b\u043a\u043d\u0443\u043b\u043e \u043c\u0435\u043d\u044f \u043a \u0438\u0434\u0435\u0435 \u0441\u0432\u043e\u0435\u0433\u043e \u043c\u0438\u043d\u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 (\u0447\u0438\u0442\u0430\u0439 \u043f\u0430\u043a\u0435\u0442\u0430, \u043d\u043e \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043e\u043d \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0435\u0434\u044a\u044f\u0432\u043b\u044f\u0442\u044c \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u043a \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435, \u0442\u043e \u0433\u043e\u0440\u0434\u043e \u043d\u0430\u0437\u043e\u0432\u0435\u043c \u043c\u0438\u043d\u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u043c),  \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u044b \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u043b \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u0438 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u043b \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0431\u043b\u043e\u043a\u0438.  <\/p>\n<p>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0431\u0443\u0434\u0435\u0442 \u0432 \u0432\u0438\u0434\u0435 composer \u043f\u0430\u043a\u0435\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043e\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432 \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u043e \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445, \u0431\u0435\u0437 \u043f\u0440\u0438\u0432\u044f\u0437\u043a\u0438 \u043a WordPress.  <\/p>\n<p>\u041c\u043e\u0442\u0438\u0432\u043e\u043c \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u0443\u044e \u0441\u0442\u0430\u0442\u044c\u044e \u0431\u044b\u043b\u043e \u0436\u0435\u043b\u0430\u043d\u0438\u0435 \u043f\u043e\u0434\u0435\u043b\u0438\u0442\u0441\u044f \u0440\u0435\u0448\u0435\u043d\u0438\u0435\u043c \u0434\u043b\u044f \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u043c\u043e\u0434\u0443\u043b\u044c\u043d\u044b\u0445 \u0431\u043b\u043e\u043a\u043e\u0432,  \u0430 \u0442\u0430\u043a\u0436\u0435 \u0436\u0435\u043b\u0430\u043d\u0438\u0435 \u0447\u0438\u0442\u0430\u0442\u0435\u043b\u044f \u0445\u0430\u0431\u0440\u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u044e \u0441\u0442\u0430\u0442\u044c\u044e, \u0447\u0442\u043e \u0441\u0440\u043e\u0434\u043d\u0438 \u0436\u0435\u043b\u0430\u043d\u0438\u044e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0441\u0432\u043e\u0439 \u043f\u0430\u043a\u0435\u0442, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043f\u043e\u0440\u043e\u0439 \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u0435\u0442 \u0443 \u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0449\u0438\u0445 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0433\u043e\u0442\u043e\u0432\u044b\u0435 \u043f\u0430\u043a\u0435\u0442\u044b composer \u0438\u043b\u0438 npm.<\/p>\n<p>\u041a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0438\u0437 \u0442\u0435\u043a\u0441\u0442\u0430 \u0432\u044b\u0448\u0435, \u044d\u0442\u043e \u043c\u043e\u044f \u043f\u0435\u0440\u0432\u0430\u044f \u0441\u0442\u0430\u0442\u044c\u044f \u043d\u0430 \u0445\u0430\u0431\u0440\u0435, \u043f\u043e-\u044d\u0442\u043e\u043c\u0443 \u043f\u0440\u043e\u0441\u044c\u0431\u0430 <s>\u043d\u0435 \u0431\u0440\u043e\u0441\u0430\u0442\u044c \u043f\u043e\u043c\u0438\u0434\u043e\u0440\u044b<\/s> \u043d\u0435 \u0441\u0443\u0434\u0438\u0442\u044c \u0441\u0442\u0440\u043e\u0433\u043e.  <\/p>\n<h2>\u041f\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0437\u0430\u0434\u0430\u0447\u0438<\/h2>\n<p>\u041f\u043e\u043d\u044f\u0442\u0438\u0435 \u0431\u043b\u043e\u043a \u043d\u0438\u0436\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e \u0441\u0443\u0442\u0438 \u0442\u0435\u043c \u0436\u0435 \u043f\u043e\u043d\u044f\u0442\u0438\u0435\u043c \u0447\u0442\u043e \u0438 \u0431\u043b\u043e\u043a \u0432 <a href=\"https:\/\/ru.bem.info\/methodology\/\" rel=\"noopener noreferrer nofollow\">BEM \u043c\u0435\u0442\u043e\u0434\u043e\u043b\u043e\u0433\u0438\u0438<\/a>,  \u0442.\u0435. \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0433\u0440\u0443\u043f\u043f\u0430 html\/js\/css \u043a\u043e\u0434\u0430 \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u043e\u0434\u043d\u0443 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044c.<\/p>\n<p>\u0413\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c html \u0438 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044f\u043c\u0438 \u0431\u043b\u043e\u043a\u043e\u0432 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0447\u0435\u0440\u0435\u0437 php, \u0447\u0442\u043e \u0433\u043e\u0432\u043e\u0440\u0438\u0442 \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u043d\u0430\u0448 \u043f\u0430\u043a\u0435\u0442 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442\u044c \u0434\u043b\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432 \u0441 \u0431\u0435\u043a\u0435\u043d\u0434\u043e\u043c \u043d\u0430 php. \u0422\u0430\u043a\u0436\u0435 \u0443\u0441\u043b\u043e\u0432\u0438\u043c\u0441\u044f \u043d\u0430 \u0431\u0435\u0440\u0435\u0433\u0443 \u0447\u0442\u043e, \u043d\u0435 \u0432\u0434\u0430\u0432\u0430\u044f\u0441\u044c \u0432 \u0441\u043f\u043e\u0440\u044b, \u043d\u0435 \u0431\u0443\u0434\u0435\u043c \u043f\u043e\u0434\u0434\u0430\u0432\u0430\u0442\u044c\u0441\u044f \u0432\u043b\u0438\u044f\u043d\u0438\u044e \u043d\u043e\u0432\u043e\u043c\u043e\u0434\u043d\u044b\u0445 \u0432\u0435\u0449\u0435\u0439, \u0442\u0430\u043a\u0438\u0445 \u043a\u0430\u043a css-in-js \u0438\u043b\u0438 bem-json \u0438 \u0431\u0443\u0434\u0435\u043c \u043f\u0440\u0438\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c\u0441\u044f <s>\u044d\u043b\u044c-\u043a\u043b\u0430\u0441\u0441\u0438\u043a\u043e<\/s> \u043a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0430, \u0442.\u0435. \u043f\u0440\u0435\u0434\u043f\u043e\u043b\u0430\u0433\u0430\u0442\u044c \u0447\u0442\u043e html, css \u0438 js \u044d\u0442\u043e \u0440\u0430\u0437\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u044b.  <\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0441\u0444\u043e\u0440\u043c\u0443\u043b\u0438\u0440\u0443\u0435\u043c \u043d\u0430\u0448\u0438 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u043a \u0431\u0443\u0434\u0443\u0449\u0435\u043c\u0443 \u043c\u0438\u043d\u0438-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0443:<\/p>\n<ul>\n<li>\n<p>\u041e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442\u044c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u0431\u043b\u043e\u043a\u043e\u0432<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 \u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u044f (\u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f) \u0431\u043b\u043e\u043a\u043e\u0432<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\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 \u0431\u043b\u043e\u043a \u0432 \u0431\u043b\u043e\u043a\u0435  \u0438 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u043e\u0434\u043d\u043e\u0433\u043e \u0431\u043b\u043e\u043a\u0430 \u043e\u0442 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u0434\u0440\u0443\u0433\u0438\u0445 \u0431\u043b\u043e\u043a\u043e\u0432 <\/p>\n<\/li>\n<\/ul>\n<h2>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043c\u0438\u043d\u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430<\/h2>\n<p>\u041a\u0430\u043a \u0443\u0441\u043b\u043e\u0432\u0438\u043b\u0438\u0441\u044c \u0432\u044b\u0448\u0435, \u0442\u0430\u043a\u0438\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u044b \u043a\u0430\u043a css \u0438 js \u0432\u0441\u0435\u0433\u0434\u0430 \u0431\u0443\u0434\u0443\u0442 \u0432 \u0432\u0438\u0434\u0435 \u043e\u0431\u044b\u0447\u043d\u044b\u0445 \u0444\u0430\u0439\u043b\u043e\u0432, \u0442.\u0435. \u044d\u0442\u043e \u0431\u0443\u0434\u0443\u0442 .js \u0438 .css \u0438\u043b\u0438 .min.css \u0438 .min.js \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u0440\u0435\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0441\u043e\u0440\u043e\u0432 \u0438 \u0441\u0431\u043e\u0440\u0449\u0438\u043a\u043e\u0432 (\u043a\u0430\u043a webpack \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440). \u0414\u043b\u044f \u0432\u0441\u0442\u0430\u0432\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 html \u043a\u043e\u0434 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0448\u0430\u0431\u043b\u043e\u043d\u0438\u0437\u0430\u0442\u043e\u0440 Twig (\u0434\u043b\u044f \u0442\u0435\u0445 \u043a\u0442\u043e \u043d\u0435 \u0437\u043d\u0430\u043a\u043e\u043c <a href=\"https:\/\/twig.symfony.com\/\" rel=\"noopener noreferrer nofollow\">\u0441\u0441\u044b\u043b\u043a\u0430<\/a>). \u041a\u0442\u043e-\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0437\u0430\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e Php \u0438 \u0441\u0430\u043c \u043f\u043e \u0441\u0435\u0431\u0435 \u0445\u043e\u0440\u043e\u0448\u0438\u0439 \u0448\u0430\u0431\u043b\u043e\u043d\u0438\u0437\u0430\u0442\u043e\u0440, \u043d\u0435 \u0431\u0443\u0434\u0435\u043c \u0432\u0434\u0430\u0432\u0430\u0442\u044c\u0441\u044f \u0432 \u0441\u043f\u043e\u0440\u044b, \u043a\u0440\u043e\u043c\u0435 \u0434\u043e\u0432\u043e\u0434\u043e\u0432 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0445 \u043d\u0430 \u0433\u043b\u0430\u0432\u043d\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 Twig, \u043e\u0442\u043c\u0435\u0447\u0443 \u0432\u0430\u0436\u043d\u044b\u0439 \u0434\u043b\u044f \u043c\u0435\u043d\u044f \u043f\u0443\u043d\u043a\u0442, \u0442\u043e \u0447\u0442\u043e \u043e\u043d \u0434\u0438\u0441\u0446\u0438\u043f\u043b\u0438\u043d\u0438\u0440\u0443\u0435\u0442, \u0442.\u0435. \u0437\u0430\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u043e\u0442\u0434\u0435\u043b\u044f\u0442\u044c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u043e\u0442 \u0432\u044b\u0432\u043e\u0434\u0430 \u0438 \u043f\u043e\u0434\u0433\u043e\u0442\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0437\u0430\u0440\u0430\u043d\u0435\u0435, \u0438 \u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e.  <\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u0440\u043e\u0434\u0443\u043c\u0430\u0435\u043c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u043d\u0430\u0448\u0435\u0433\u043e \u043c\u0438\u043d\u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 \u0431\u043e\u043b\u0435\u0435 \u0434\u0435\u0442\u0430\u043b\u044c\u043d\u043e.  <\/p>\n<ol>\n<li>\n<p> \u0411\u043b\u043e\u043a<\/p>\n<p> \u041a\u0430\u0436\u0434\u044b\u0439 \u0431\u043b\u043e\u043a \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u0442\u044c \u0438\u0437:<\/p>\n<ol>\n<li>\n<p>\u0421\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 (css\/js\/twig)<\/p>\n<\/li>\n<li>\n<p>\u041a\u043b\u0430\u0441\u0441\u0430 \u043c\u043e\u0434\u0435\u043b\u0438 (\u0435\u0433\u043e \u043f\u043e\u043b\u044f \u043c\u044b \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u043a\u0430\u043a \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f twig \u0448\u0430\u0431\u043b\u043e\u043d\u0430)<\/p>\n<\/li>\n<li>\n<p> \u041a\u043b\u0430\u0441\u0441\u0430 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0435\u0440\u0430 (\u043e\u043d \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u0432\u0435\u0447\u0430\u0442\u044c \u0437\u0430 \u043d\u0430\u0448\u0438 \u0440\u0435\u0441\u0443\u0440\u0441\u044b, \u0438\u0445 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0434\u0440\u0443\u0433 \u043e\u0442 \u0434\u0440\u0443\u0433\u0430 \u0438 \u0441\u0432\u044f\u0437\u044b\u0432\u0430\u0442\u044c \u043c\u043e\u0434\u0435\u043b\u044c \u0441 twig \u0448\u0430\u0431\u043b\u043e\u043d\u043e\u043c)<\/p>\n<\/li>\n<\/ol>\n<\/li>\n<li>\n<p> \u0412\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043a\u043b\u0430\u0441\u0441\u044b : \u041a\u043b\u0430\u0441\u0441 Settings (\u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u043f\u0443\u0442\u044c \u043a \u0431\u043b\u043e\u043a\u0430\u043c, \u0438\u0445 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e \u0438\u043c\u0435\u043d \u0438 \u0442.\u0434.), \u043a\u043b\u0430\u0441\u0441 \u043e\u0431\u0435\u0440\u0442\u043a\u0430 \u0434\u043b\u044f Twig \u043f\u0430\u043a\u0435\u0442\u0430<\/p>\n<\/li>\n<li>\n<p> Blocks \u043a\u043b\u0430\u0441\u0441<\/p>\n<p> \u0421\u0432\u044f\u0437\u0443\u044e\u0449\u0438\u0439 \u043a\u043b\u0430\u0441\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 :<\/p>\n<ol>\n<li>\n<p> \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043a\u043b\u0430\u0441\u0441\u044b (Settings, Twig)<\/p>\n<\/li>\n<li>\n<p>\u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0440\u0435\u043d\u0434\u0435\u0440\u0430 \u0431\u043b\u043e\u043a\u0430<\/p>\n<\/li>\n<li>\n<p>\u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0431\u043b\u043e\u043a\u043e\u0432, \u0447\u0442\u043e\u0431\u044b \u0438\u043c\u0435\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0438\u0445 \u0440\u0435\u0441\u0443\u0440\u0441\u044b (css\/js)<\/p>\n<\/li>\n<li>\n<p>\u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044c \u0432\u0441\u0435 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u044b (\u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0437\u0430\u0434\u0435\u043b \u043d\u0430 \u0431\u0443\u0434\u0443\u0449\u0435\u0435, \u044d\u0442\u043e \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0432\u044b\u0445\u043e\u0434\u0438\u0442 \u0437\u0430 \u0440\u0430\u043c\u043a\u0438 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0441\u0442\u0430\u0442\u044c\u0438, \u0441\u043a\u0430\u0436\u0443 \u043f\u0440\u043e\u0441\u0442\u043e \u0447\u0442\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u043e\u0432 \u0438 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f)<\/p>\n<\/li>\n<\/ol>\n<\/li>\n<\/ol>\n<h2> \u0422\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u043a \u0431\u043b\u043e\u043a\u0430\u043c<\/h2>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043a\u043e\u0433\u0434\u0430 \u043c\u044b \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043b\u0438\u0441\u044c \u0441\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043e\u0439 \u043f\u0440\u0438\u0448\u043b\u043e \u0432\u0440\u0435\u043c\u044f <s>\u0437\u0430\u0436\u0435\u0447\u044c<\/s> \u043e\u043f\u0440\u0430\u0432\u0434\u0430\u0442\u044c \u0441\u043b\u043e\u0432\u043e \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0432 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0438 \u0434\u043b\u044f \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0430\u043a\u0435\u0442\u0430, \u0430 \u0438\u043c\u0435\u043d\u043d\u043e \u2013 \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u043a \u043a\u043e\u0434\u0443 \u043d\u0430\u0448\u0438\u0445 \u0431\u043b\u043e\u043a\u043e\u0432:<\/p>\n<ul>\n<li>\n<p> php 7.4+<\/p>\n<\/li>\n<li>\n<p> \u0412\u0441\u0435 \u0431\u043b\u043e\u043a\u0438 \u0434\u043e\u043b\u0436\u043d\u044b \u0438\u043c\u0435\u0442\u044c \u043e\u0434\u043d\u0443 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0443\u044e \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e<\/p>\n<\/li>\n<li>\n<p> \u041a\u043b\u0430\u0441\u0441\u044b \u043c\u043e\u0434\u0435\u043b\u0435\u0439 \u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u043e\u0432 \u0434\u043e\u043b\u0436\u043d\u044b \u0438\u043c\u0435\u0442\u044c PSR-4 \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u043e\u0435 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e \u0438\u043c\u0435\u043d \u0441 \u0430\u0432\u0442\u043e\u0437\u0430\u0433\u0440\u0443\u0437\u0447\u0438\u043a\u043e\u043c (<a href=\"https:\/\/www.php-fig.org\/psr\/psr-4\/\" rel=\"noopener noreferrer nofollow\">PSR-4<\/a> \u0434\u0435 \u0444\u0430\u043a\u0442\u043e \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442, \u0435\u0441\u043b\u0438 \u0432\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0435 \u0430\u0432\u0442\u043e\u0437\u0430\u0433\u0440\u0443\u0437\u0447\u0438\u043a \u043e\u0442 composer, \u0442.\u0435. \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0435 autoload\/psr4 \u0434\u0438\u0440\u0435\u043a\u0442\u0438\u0432\u0443 \u0432 \u0432\u0430\u0448\u0435\u043c composer.json \u0442\u043e \u0432\u0430\u0448 \u043f\u0440\u043e\u0435\u043a\u0442 \u0443\u0436\u0435 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u044d\u0442\u043e\u043c\u0443 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044e)  <\/p>\n<\/li>\n<li>\n<p> \u0421\u043e\u0433\u043b\u0430\u0448\u0435\u043d\u0438\u0435 \u043e\u0431 \u0438\u043c\u0435\u043d\u0430\u0445:<\/p>\n<ul>\n<li>\n<p>\u0418\u043c\u044f \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430 \u0434\u043e\u043b\u0436\u043d\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u2018_C\u2019 \u0441\u0443\u0444\u0444\u0438\u043a\u0441<\/p>\n<\/li>\n<li>\n<p> \u041a\u043b\u0430\u0441\u0441 \u043c\u043e\u0434\u0435\u043b\u0438 \u0434\u043e\u043b\u0436\u0435\u043d \u0438\u043c\u0435\u0442\u044c \u0442\u043e \u0436\u0435 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e \u0438\u043c\u0435\u043d \u0438 \u0442\u043e \u0436\u0435 \u0438\u043c\u044f (\u0431\u0435\u0437 \u0441\u0443\u0444\u0444\u0438\u043a\u0441\u0430) \u0447\u0442\u043e \u0438 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440<\/p>\n<\/li>\n<li>\n<p> \u0418\u043c\u0435\u043d\u0430 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u0434\u043e\u043b\u0436\u043d\u044b \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0438\u043c\u0435\u043d\u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430, \u043d\u043e \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u043e\u0442\u043b\u0438\u0447\u0438\u044f\u043c\u0438:<\/p>\n<ul>\n<li>\n<p> \u0411\u0435\u0437 \u0441\u0443\u0444\u0444\u0438\u043a\u0441\u0430 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430<\/p>\n<\/li>\n<li>\n<p> \u0412\u0435\u0440\u0431\u043b\u044e\u0436\u044c\u044f \u043d\u043e\u0442\u0430\u0446\u0438\u044f \u0432 \u0438\u043c\u0435\u043d\u0438 \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c \u0437\u0430\u043c\u0435\u043d\u0435\u043d\u0430 \u043d\u0430 \u0442\u0438\u0440\u0435 (CamelCase = camel-case)<\/p>\n<\/li>\n<li>\n<p>\u041d\u0438\u0436\u043d\u0435\u0435 \u043f\u043e\u0434\u0447\u0435\u0440\u043a\u0438\u0432\u0430\u043d\u0438\u0435 \u0432 \u0438\u043c\u0435\u043d\u0438 \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u0437\u0430\u043c\u0435\u043d\u0435\u043d\u043e \u043d\u0430 \u0442\u0438\u0440\u0435 (just_block = just-block)<\/p>\n<\/li>\n<li>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043f\u043e \u043f\u0440\u0430\u0432\u0438\u043b\u0430\u043c \u0432\u044b\u0448\u0435 \u0438\u043c\u044f \u0440\u0435\u0441\u0443\u0440\u0441\u0430 \u0441 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u043e\u043c \u2018Block_Theme_Main_C\u2019 \u0431\u0443\u0434\u0435\u0442 \u2018block\u2014theme&#8212;main\u2019<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h2>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f<\/h2>\n<p> \u041f\u0440\u0438\u0448\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u043f\u0435\u0440\u0435\u0439\u0442\u0438 \u043a \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043d\u0430\u0448\u0435\u0439 \u0438\u0434\u0435\u0438, \u0442.\u0435. \u043a \u043a\u043e\u0434\u0443.  <\/p>\n<p>\u041d\u0438\u0436\u0435 \u0447\u0430\u0441\u0442\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 (\u043a\u043b\u0430\u0441\u0441\u044b) \u0431\u0443\u0434\u0443\u0442 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 : \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u043e\u0435 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435, \u043a\u043e\u0434 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0438 \u043a\u043e\u0434 \u0442\u0435\u0441\u0442\u043e\u0432. \u0421\u043e\u0433\u043b\u0430\u0441\u0435\u043d \u0441 \u043b\u044e\u0434\u044c\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0433\u043e\u0432\u043e\u0440\u044f\u0442 \u0447\u0442\u043e \u0442\u0435\u0441\u0442\u044b \u0435\u0441\u0442\u044c \u043b\u0443\u0447\u0448\u0430\u044f \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f, \u043e\u0434\u043d\u0430\u043a\u043e \u043a \u0441\u0432\u043e\u0435\u043c\u0443 \u0441\u0442\u044b\u0434\u0443 \u044f \u043d\u0430\u0447\u0430\u043b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438\u0445 \u0432 \u0441\u0432\u043e\u0438\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445 \u043d\u0435\u0434\u0430\u0432\u043d\u043e, \u043f\u043e-\u044d\u0442\u043e\u043c\u0443 \u043d\u0435 \u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u043c\u043e\u0438 \u0441\u0442\u0430\u0440\u0430\u043d\u0438\u044f \u0438\u0445 \u0438\u043c\u0435\u043d\u0430 \u0438\u043b\u0438 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043c\u043e\u0433\u0443\u0442 <s>\u043f\u043e\u0432\u0435\u0440\u0433\u043d\u0443\u0442\u044c \u0432 \u0448\u043e\u043a<\/s> \u0441\u0431\u0438\u0432\u0430\u0442\u044c \u0441 \u0442\u043e\u043b\u043a\u0443, \u043f\u0440\u043e\u0441\u044c\u0431\u0430 \u043d\u0435 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c \u0431\u043b\u0438\u0437\u043a\u043e \u043a \u0441\u0435\u0440\u0434\u0446\u0443.<\/p>\n<p><strong> FIELDS_READER<\/strong><\/p>\n<p>\u0412\u0441\u0435 \u043d\u0430\u0448\u0430 \u043c\u0430\u0433\u0438\u044f \u043f\u0440\u0438 \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 \u043c\u043e\u0434\u0435\u043b\u044f\u043c\u0438 \u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430\u043c\u0438 \u0431\u0443\u0434\u0435\u0442 \u0441\u0442\u0440\u043e\u0438\u0442\u0441\u044f \u043d\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u2018get_class_vars\u2019 \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442 \u043d\u0430\u043c \u0438\u043c\u0435\u043d\u0430 \u043f\u043e\u043b\u0435\u0439 \u043a\u043b\u0430\u0441\u0441\u0430 \u0438 \u043d\u0430 \u2018ReflectionProperty\u2019 \u043a\u043b\u0430\u0441\u0441\u0435, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442 \u043d\u0430\u043c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e\u0431 \u044d\u0442\u0438\u0445 \u043f\u043e\u043b\u044f\u0445, \u0442\u0430\u043a\u0443\u044e \u043a\u0430\u043a \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u043f\u043e\u043b\u044f  (protected\/public) \u0438 \u0435\u0433\u043e \u0442\u0438\u043f. \u041c\u044b \u0431\u0443\u0434\u0435\u043c \u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0442\u043e\u043b\u044c\u043a\u043e \u043e protected \u043f\u043e\u043b\u044f\u0445.<\/p>\n<p>\u0422\u0430\u043a\u0436\u0435 \u0443\u043f\u0440\u043e\u0441\u0442\u0438\u043c \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0443\u044e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443, \u0434\u043e\u0431\u0430\u0432\u0438\u0432 \u0430\u0432\u0442\u043e\u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0445 \u043f\u043e\u043b\u0435\u0439 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e, \u044d\u0442\u043e \u0438\u0437\u0431\u0430\u0432\u0438\u0442 \u043d\u0430\u0441 \u043e\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438\u0445 \u0432 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0435 \u0432\u0440\u0443\u0447\u043d\u0443\u044e, \u0447\u0442\u043e \u043f\u0440\u0438 \u0431\u043e\u043b\u044c\u0448\u043e\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0435 \u0431\u043b\u043e\u043a\u043e\u0432 \u0441\u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0442 \u043d\u0430\u0448\u0435 \u0432\u0440\u0435\u043c\u044f.<\/p>\n<details class=\"spoiler\">\n<summary>FIELDS_READER.php <\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php  declare( strict_types=1 );  namespace LightSource\\FrontBlocksFramework;  use Exception; use ReflectionProperty;  abstract class FIELDS_READER {  \tprivate array $_fieldsInfo;  \tpublic function __construct() {  \t\t$this-&gt;_fieldsInfo = [];  \t\t$this-&gt;_readFieldsInfo(); \t\t$this-&gt;_autoInitFields();  \t}  \tfinal protected function _getFieldsInfo(): array { \t\treturn $this-&gt;_fieldsInfo; \t}  \tprotected function _getFieldType( string $fieldName ): ?string {  \t\t$fieldType = null;  \t\ttry { \t\t\t\/\/ used static for child support \t\t\t$property = new ReflectionProperty( static::class, $fieldName ); \t\t} catch ( Exception $ex ) { \t\t\treturn $fieldType; \t\t}  \t\tif ( ! $property-&gt;isProtected() ) { \t\t\treturn $fieldType; \t\t}  \t\treturn $property-&gt;getType() ? \t\t\t$property-&gt;getType()-&gt;getName() : \t\t\t''; \t}  \tprivate function _readFieldsInfo(): void {  \t\t\/\/ get protected fields without the '__' prefix  \t\t$fieldNames = array_keys( get_class_vars( static::class ) ); \t\t$fieldNames = array_filter( $fieldNames, function ( $fieldName ) {  \t\t\t$prefix = substr( $fieldName, 0, 2 );  \t\t\treturn '__' !== $prefix; \t\t} );  \t\tforeach ( $fieldNames as $fieldName ) {  \t\t\t$fieldType = $this-&gt;_getFieldType( $fieldName );  \t\t\t\/\/ only protected fields \t\t\tif ( is_null( $fieldType ) ) { \t\t\t\tcontinue; \t\t\t}  \t\t\t$this-&gt;_fieldsInfo[ $fieldName ] = $fieldType;  \t\t}  \t}  \tprivate function _autoInitFields(): void {  \t\tforeach ( $this-&gt;_fieldsInfo as $fieldName =&gt; $fieldType ) {  \t\t\t\/\/ ignore fields without a type \t\t\tif ( ! $fieldType ) { \t\t\t\tcontinue; \t\t\t}  \t\t\t$defaultValue = null;  \t\t\tswitch ( $fieldType ) { \t\t\t\tcase 'int': \t\t\t\tcase 'float': \t\t\t\t\t$defaultValue = 0; \t\t\t\t\tbreak; \t\t\t\tcase 'bool': \t\t\t\t\t$defaultValue = false; \t\t\t\t\tbreak; \t\t\t\tcase 'string': \t\t\t\t\t$defaultValue = ''; \t\t\t\t\tbreak; \t\t\t\tcase 'array': \t\t\t\t\t$defaultValue = []; \t\t\t\t\tbreak; \t\t\t}  \t\t\ttry {  \t\t\t\tif ( is_subclass_of( $fieldType, MODEL::class ) || \t\t\t\t     is_subclass_of( $fieldType, CONTROLLER::class ) ) { \t\t\t\t\t$defaultValue = new $fieldType(); \t\t\t\t}  \t\t\t} catch ( Exception $ex ) { \t\t\t\t$defaultValue = null; \t\t\t}  \t\t\t\/\/ ignore fields with a custom type (null by default) \t\t\tif ( is_null( $defaultValue ) ) { \t\t\t\tcontinue; \t\t\t}  \t\t\t$this-&gt;{$fieldName} = $defaultValue;  \t\t}  \t}  } <\/code><\/pre>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>FIELDS_READERTest.php<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php  declare( strict_types=1 );  namespace LightSource\\FrontBlocksFramework\\Tests\\unit;  use Codeception\\Test\\Unit; use LightSource\\FrontBlocksFramework\\CONTROLLER; use LightSource\\FrontBlocksFramework\\FIELDS_READER; use LightSource\\FrontBlocksFramework\\MODEL;  class FIELDS_READERTest extends Unit {  \tpublic function testReadProtectedField() {  \t\t$fieldsReader = new class extends FIELDS_READER {  \t\t\tprotected $_loadedField;  \t\t\tpublic function __construct() {  \t\t\t\tparent::__construct();  \t\t\t}  \t\t\tpublic function getFields() { \t\t\t\treturn $this-&gt;_getFieldsInfo(); \t\t\t}  \t\t};  \t\t$this-&gt;assertEquals( [ \t\t\t'_loadedField' =&gt; '', \t\t], $fieldsReader-&gt;getFields() );  \t}  \tpublic function testIgnoreReadProtectedPrefixedField() {  \t\t$fieldsReader = new class extends FIELDS_READER {  \t\t\tprotected $__unloadedField;  \t\t\tpublic function __construct() {  \t\t\t\tparent::__construct();  \t\t\t}  \t\t\tpublic function getFields() { \t\t\t\treturn $this-&gt;_getFieldsInfo(); \t\t\t}  \t\t};  \t\t$this-&gt;assertEquals( [], $fieldsReader-&gt;getFields() );  \t}  \tpublic function testIgnoreReadPublicField() {  \t\t$fieldsReader = new class extends FIELDS_READER {  \t\t\tpublic $unloadedField;  \t\t\tpublic function __construct() {  \t\t\t\tparent::__construct();  \t\t\t}  \t\t\tpublic function getFields() { \t\t\t\treturn $this-&gt;_getFieldsInfo(); \t\t\t}  \t\t};  \t\t$this-&gt;assertEquals( [ \t\t], $fieldsReader-&gt;getFields() );  \t}  \tpublic function testIgnoreReadPrivateField() {  \t\t$fieldsReader = new class extends FIELDS_READER {  \t\t\tprivate $unloadedField;  \t\t\tpublic function __construct() {  \t\t\t\tparent::__construct();  \t\t\t}  \t\t\tpublic function getFields() { \t\t\t\treturn $this-&gt;_getFieldsInfo(); \t\t\t}  \t\t};  \t\t$this-&gt;assertEquals( [ \t\t], $fieldsReader-&gt;getFields() );  \t}  \tpublic function testReadFieldWithType() {  \t\t$fieldsReader = new class extends FIELDS_READER {  \t\t\tprotected string $_loadedField;  \t\t\tpublic function __construct() {  \t\t\t\tparent::__construct();  \t\t\t}  \t\t\tpublic function getFields() { \t\t\t\treturn $this-&gt;_getFieldsInfo(); \t\t\t}  \t\t};  \t\t$this-&gt;assertEquals( [ \t\t\t'_loadedField' =&gt; 'string', \t\t], $fieldsReader-&gt;getFields() );  \t}  \tpublic function testReadFieldWithoutType() {  \t\t$fieldsReader = new class extends FIELDS_READER {  \t\t\tprotected $_loadedField;  \t\t\tpublic function __construct() {  \t\t\t\tparent::__construct();  \t\t\t}  \t\t\tpublic function getFields() { \t\t\t\treturn $this-&gt;_getFieldsInfo(); \t\t\t}  \t\t};  \t\t$this-&gt;assertEquals( [ \t\t\t'_loadedField' =&gt; '', \t\t], $fieldsReader-&gt;getFields() );  \t}  \t\/\/\/\/  \tpublic function testAutoInitIntField() {  \t\t$fieldsReader = new class extends FIELDS_READER {  \t\t\tprotected int $_int;  \t\t\tpublic function __construct() {  \t\t\t\tparent::__construct();  \t\t\t}  \t\t\tpublic function getInt() { \t\t\t\treturn $this-&gt;_int; \t\t\t}  \t\t};  \t\t$this-&gt;assertTrue( 0 === $fieldsReader-&gt;getInt() );  \t}  \tpublic function testAutoInitFloatField() {  \t\t$fieldsReader = new class extends FIELDS_READER {  \t\t\tprotected float $_float;  \t\t\tpublic function __construct() {  \t\t\t\tparent::__construct();  \t\t\t}  \t\t\tpublic function getFloat() { \t\t\t\treturn $this-&gt;_float; \t\t\t}  \t\t};  \t\t$this-&gt;assertTrue( 0.0 === $fieldsReader-&gt;getFloat() );  \t}  \tpublic function testAutoInitStringField() {  \t\t$fieldsReader = new class extends FIELDS_READER {  \t\t\tprotected string $_string;  \t\t\tpublic function __construct() {  \t\t\t\tparent::__construct();  \t\t\t}  \t\t\tpublic function getString() { \t\t\t\treturn $this-&gt;_string; \t\t\t}  \t\t};  \t\t$this-&gt;assertTrue( '' === $fieldsReader-&gt;getString() );  \t}  \tpublic function testAutoInitBoolField() {  \t\t$fieldsReader = new class extends FIELDS_READER {  \t\t\tprotected bool $_bool;  \t\t\tpublic function __construct() {  \t\t\t\tparent::__construct();  \t\t\t}  \t\t\tpublic function getBool() { \t\t\t\treturn $this-&gt;_bool; \t\t\t}  \t\t};  \t\t$this-&gt;assertTrue( false === $fieldsReader-&gt;getBool() );  \t}  \tpublic function testAutoInitArrayField() {  \t\t$fieldsReader = new class extends FIELDS_READER {  \t\t\tprotected array $_array;  \t\t\tpublic function __construct() {  \t\t\t\tparent::__construct();  \t\t\t}  \t\t\tpublic function getArray() { \t\t\t\treturn $this-&gt;_array; \t\t\t}  \t\t};  \t\t$this-&gt;assertTrue( [] === $fieldsReader-&gt;getArray() );  \t}  \tpublic function testAutoInitModelField() {  \t\t$testModel        = new class extends MODEL { \t\t}; \t\t$testModelClass   = get_class( $testModel ); \t\t$fieldsReader     = new class ( $testModelClass ) extends FIELDS_READER {  \t\t\tprotected $_model; \t\t\tprivate $_testClass;  \t\t\tpublic function __construct( $testClass ) {  \t\t\t\t$this-&gt;_testClass = $testClass; \t\t\t\tparent::__construct();  \t\t\t}  \t\t\tpublic function _getFieldType( string $fieldName ): ?string { \t\t\t\treturn ( '_model' === $fieldName ? \t\t\t\t\t$this-&gt;_testClass : \t\t\t\t\tparent::_getFieldType( $fieldName ) ); \t\t\t}  \t\t\tpublic function getModel() { \t\t\t\treturn $this-&gt;_model; \t\t\t}  \t\t}; \t\t$actualModelClass = $fieldsReader-&gt;getModel() ? \t\t\tget_class( $fieldsReader-&gt;getModel() ) : \t\t\t'';  \t\t$this-&gt;assertEquals( $actualModelClass, $testModelClass );  \t}  \tpublic function testAutoInitControllerField() {  \t\t$testController      = new class extends CONTROLLER { \t\t}; \t\t$testControllerClass = get_class( $testController ); \t\t$fieldsReader        = new class ( $testControllerClass ) extends FIELDS_READER {  \t\t\tprotected $_controller; \t\t\tprivate $_testClass;  \t\t\tpublic function __construct( $testControllerClass ) {  \t\t\t\t$this-&gt;_testClass = $testControllerClass; \t\t\t\tparent::__construct();  \t\t\t}  \t\t\tpublic function _getFieldType( string $fieldName ): ?string { \t\t\t\treturn ( '_controller' === $fieldName ? \t\t\t\t\t$this-&gt;_testClass : \t\t\t\t\tparent::_getFieldType( $fieldName ) ); \t\t\t}  \t\t\tpublic function getController() { \t\t\t\treturn $this-&gt;_controller; \t\t\t}  \t\t}; \t\t$actualModelClass    = $fieldsReader-&gt;getController() ? \t\t\tget_class( $fieldsReader-&gt;getController() ) : \t\t\t'';  \t\t$this-&gt;assertEquals( $actualModelClass, $testControllerClass );  \t}  \tpublic function testIgnoreInitFieldWithoutType() {  \t\t$fieldsReader = new class extends FIELDS_READER {  \t\t\tprotected $_default;  \t\t\tpublic function __construct() {  \t\t\t\tparent::__construct();  \t\t\t}  \t\t\tpublic function getDefault() { \t\t\t\treturn $this-&gt;_default; \t\t\t}  \t\t};  \t\t$this-&gt;assertTrue( null === $fieldsReader-&gt;getDefault() );  \t}  } <\/code><\/pre>\n<\/div>\n<\/details>\n<p><strong> MODEL<\/strong><\/p>\n<p>\u0414\u0430\u043d\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 \u043f\u043e \u0441\u0443\u0442\u0438 \u043b\u0438\u0448\u044c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0430\u044f \u043e\u0431\u0435\u0440\u0442\u043a\u0430 \u0434\u043b\u044f \u043a\u043b\u0430\u0441\u0441\u0430 FIELDS_READER, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043f\u043e\u043b\u0435 \u2018_isLoaded\u2019, \u0447\u0442\u043e \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043c\u043e\u0434\u0435\u043b\u0438, \u043e\u043d\u043e \u043f\u0440\u0438\u0433\u043e\u0434\u0438\u0442\u0441\u044f \u043d\u0430\u043c \u043a\u043e\u0433\u0434\u0430 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 twig, \u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u2018getFields\u2019, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043c\u0430\u0441\u0441\u0438\u0432 \u0441\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u043c\u0438 protected \u043f\u043e\u043b\u0435\u0439, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043a\u043b\u044e\u0447\u0438 \u044d\u0442\u043e \u0438\u0445 \u0438\u043c\u0435\u043d\u0430.<\/p>\n<details class=\"spoiler\">\n<summary>MODEL.php<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php  declare( strict_types=1 );  namespace LightSource\\FrontBlocksFramework;  abstract class MODEL extends FIELDS_READER {  \tprivate bool $_isLoaded;  \tpublic function __construct() {  \t\tparent::__construct();  \t\t$this-&gt;_isLoaded = false;  \t}  \tfinal public function isLoaded(): bool { \t\treturn $this-&gt;_isLoaded; \t}  \tpublic function getFields(): array {  \t\t$args = [];  \t\t$fieldsInfo = $this-&gt;_getFieldsInfo();  \t\tforeach ( $fieldsInfo as $fieldName =&gt; $fieldType ) { \t\t\t$args[ $fieldName ] = $this-&gt;{$fieldName}; \t\t}  \t\treturn $args; \t}  \tfinal protected function _load(): void { \t\t$this-&gt;_isLoaded = true; \t}  } <\/code><\/pre>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>MODELTest.php<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php  declare( strict_types=1 );  namespace LightSource\\FrontBlocksFramework\\Tests\\unit;  use Codeception\\Test\\Unit; use LightSource\\FrontBlocksFramework\\MODEL;  class MODELTest extends Unit {  \tpublic function testGetFields() {  \t\t$model = new class extends MODEL {  \t\t\tprotected string $_field1;  \t\t\tpublic function __construct() {  \t\t\t\tparent::__construct();  \t\t\t}  \t\t\tpublic function update() { \t\t\t\t$this-&gt;_field1 = 'just string'; \t\t\t}  \t\t};  \t\t$model-&gt;update();  \t\t$this-&gt;assertEquals( [ \t\t\t'_field1'   =&gt; 'just string', \t\t], $model-&gt;getFields() );  \t}  } <\/code><\/pre>\n<\/div>\n<\/details>\n<p><strong>CONTROLLER<\/strong><\/p>\n<p>\u0414\u0430\u043d\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 \u0442\u0430\u043a\u0436\u0435 \u043a\u0430\u043a \u0438 MODEL \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u043a\u043b\u0430\u0441\u0441 FIELDS_READER, \u043e\u0434\u043d\u0430\u043a\u043e \u0438\u043c\u0435\u0435\u0442 \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u0432\u0430\u0436\u043d\u044b\u0435 \u0437\u0430\u0434\u0430\u0447\u0438. \u0421\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0434\u0432\u0430 \u043f\u043e\u043b\u044f \u2013 \u043c\u043e\u0434\u0435\u043b\u044c \u0438 \u043c\u0430\u0441\u0441\u0438\u0432 \u2018__external\u2019, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0438\u0433\u043e\u0434\u0438\u0442\u0441\u044f \u043d\u0430\u043c \u0434\u0430\u043b\u0435\u0435 \u043f\u0440\u0438 \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 twig \u0448\u0430\u0431\u043b\u043e\u043d\u043e\u043c.<\/p>\n<p>\u0421\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u043c\u0435\u0442\u043e\u0434 GetResourceInfo \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0440\u0435\u0441\u0443\u0440\u0441\u0430\u0445 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0431\u043b\u043e\u043a\u0430 (twig,css,js) , \u0442\u0430\u043a\u0443\u044e \u043a\u0430\u043a \u0438\u043c\u044f \u0440\u0435\u0441\u0443\u0440\u0441\u0430 \u0438\u043b\u0438 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043f\u0443\u0442\u044c \u043a \u043d\u0435\u043c\u0443 (\u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u044d\u0442\u043e \u0438\u0437 \u0438\u043c\u0435\u043d\u0438 \u0438 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u0430 \u0438\u043c\u0435\u043d \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430 \u0431\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u0441\u043e\u0431\u043b\u044e\u0434\u0435\u043d\u0438\u044e \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0439 \u0432\u044b\u0448\u0435).<\/p>\n<p>\u041c\u0435\u0442\u043e\u0434 getTemplateArgs \u0431\u0443\u0434\u0435\u0442 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f twig \u0448\u0430\u0431\u043b\u043e\u043d\u0430, \u044d\u0442\u043e \u0432\u0441\u0435 protected \u043f\u043e\u043b\u044f \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0439 \u043c\u043e\u0434\u0435\u043b\u0438 (\u0431\u0435\u0437 \u043f\u0440\u0435\u0444\u0438\u043a\u0441\u0430 \u2018_\u2019 \u0435\u0441\u043b\u0438 \u0435\u0441\u0442\u044c) \u0438 \u0434\u0432\u0430 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u043f\u043e\u043b\u044f, _template  \u0438 _isLoaded, \u043f\u0435\u0440\u0432\u043e\u0435 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u043f\u0443\u0442\u044c \u043a \u0448\u0430\u0431\u043b\u043e\u043d\u0443, \u0430 \u0432\u0442\u043e\u0440\u043e\u0435 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043c\u043e\u0434\u0435\u043b\u0438. \u0422\u0430\u043a\u0436\u0435 \u0432 \u044d\u0442\u043e\u043c \u043c\u0435\u0442\u043e\u0434\u0435 \u043c\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0431\u043b\u043e\u043a \u0432 \u0431\u043b\u043e\u043a\u0435 (\u0442.\u0435. \u0438\u043c\u0435\u0442\u044c \u043a\u043b\u0430\u0441\u0441 Model \u0432 \u0434\u0440\u0443\u0433\u043e\u043c \u043a\u043b\u0430\u0441\u0441\u0435 Model \u043a\u0430\u043a \u043f\u043e\u043b\u0435) &#8212; \u043c\u044b \u0441\u043e\u0435\u0434\u0438\u043d\u044f\u0435\u043c \u043f\u043e\u043b\u044f \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430 \u0438 \u043f\u043e\u043b\u044f \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0439 \u043c\u043e\u0434\u0435\u043b\u0438 \u043f\u043e \u0438\u043c\u0435\u043d\u0438 : \u0442.\u0435. \u0435\u0441\u043b\u0438 \u043a\u0430\u0436\u0434\u043e\u043c\u0443 \u043f\u043e\u043b\u044e \u0441 \u0442\u0438\u043f\u043e\u043c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u043c\u044b \u043d\u0430\u0445\u043e\u0434\u0438\u043c \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0435 \u043f\u043e\u043b\u0435 \u0432 \u043c\u043e\u0434\u0435\u043b\u0438 (\u0441 \u0442\u0438\u043f\u043e\u043c \u043c\u043e\u0434\u0435\u043b\u044c), \u0442\u043e \u043c\u044b \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u043f\u043e\u043b\u0435 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u043c\u043e\u0434\u0435\u043b\u044c\u044e \u0438 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c  \u043c\u0435\u0442\u043e\u0434  getTemplateArgs \u0443 \u044d\u0442\u043e\u0433\u043e \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430, \u043f\u043e\u043b\u0443\u0447\u0430\u044f \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0432\u0441\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u044d\u0442\u043e\u0433\u043e \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u043e\u0433\u043e \u0431\u043b\u043e\u043a\u0430.<\/p>\n<p>\u041c\u0435\u0442\u043e\u0434 getDependencies \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u0438 \u043d\u0430\u0448\u0438\u0445 \u043f\u043e\u043b\u0435\u0439 \u0441 \u0442\u0438\u043f\u043e\u043c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u0440\u0435\u043a\u0443\u0440\u0441\u0438\u0432\u043d\u043e (\u0441 \u043e\u0431\u0445\u043e\u0434\u043e\u043c \u0432\u0441\u0435\u0445 \u043f\u043e\u0434\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439) \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043d\u0430\u043c \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0439 (\u0442.\u0435. \u0431\u0435\u0437 \u043f\u043e\u0432\u0442\u043e\u0440\u0435\u043d\u0438\u0439) \u0441\u043f\u0438\u0441\u043e\u043a \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0445 \u043a\u043b\u0430\u0441\u0441\u043e\u0432-\u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u043e\u0432, \u0447\u0442\u043e \u043f\u043e\u043c\u043e\u0433\u0430\u0435\u0442 \u043d\u0430\u043c \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u043e\u0434\u043d\u043e\u0433\u043e \u0431\u043b\u043e\u043a\u0430 \u043e\u0442 \u0434\u0440\u0443\u0433\u043e\u0433\u043e.<\/p>\n<p>\u0422\u0430\u043a\u0436\u0435 \u043e\u0442\u043c\u0435\u0447\u0443 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442, \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0443\u044e \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u043f\u043e\u043b\u044f \u043c\u043e\u0434\u0435\u043b\u0438 \u0432 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0435 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430, \u0442.\u0435. \u0435\u0441\u043b\u0438 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043a\u043b\u0430\u0441\u0441 \u0441 \u0442\u0430\u043a\u0438\u043c \u0436\u0435 \u0438\u043c\u0435\u043d\u0435\u043c \u043a\u0430\u043a \u0443 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430, \u043d\u043e \u0431\u0435\u0437 \u0441\u0443\u0444\u0444\u0438\u043a\u0441\u0430 (\u0441\u043c\u043e\u0442\u0440\u0438 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u0432\u044b\u0448\u0435), \u0442\u043e \u044d\u0442\u043e \u043f\u043e\u043b\u0435 \u0431\u0443\u0434\u0435\u0442 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u043c \u044d\u0442\u043e\u0433\u043e \u043a\u043b\u0430\u0441\u0441\u0430. \u042d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u043b\u0438\u0448\u043d\u0435\u0433\u043e \u043a\u043e\u0434\u0430 \u0432 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u043c (\u0442.\u0435. \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043c\u043e\u0434\u0435\u043b\u0438 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043e\u0442 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430) \u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u043b\u044f \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f (\u044d\u0442\u043e \u0432\u044b\u0445\u043e\u0434\u0438\u0442 \u0437\u0430 \u0440\u0430\u043c\u043a\u0438 \u043d\u0430\u0448\u0435\u0439 \u0441\u0442\u0430\u0442\u044c\u0438).<\/p>\n<details class=\"spoiler\">\n<summary>CONTROLLER.php<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php  declare( strict_types=1 );  namespace LightSource\\FrontBlocksFramework;  use Exception;  abstract class CONTROLLER extends FIELDS_READER {  \tconst TEMPLATE_KEY__TEMPLATE = '_template'; \tconst TEMPLATE_KEY__IS_LOADED = '_isLoaded';  \tprivate ?MODEL $_model; \t\/\/ using the prefix to prevent load this field \tprotected array $__external;  \tpublic function __construct( ?MODEL $model = null ) {  \t\tparent::__construct();  \t\t$this-&gt;_model     = $model; \t\t$this-&gt;__external = [];  \t\t$this-&gt;_autoInitModel();  \t}  \tfinal public static function GetResourceInfo( Settings $settings, string $controllerClass = '' ): array {  \t\t\/\/ using static for children support \t\t$controllerClass = ! $controllerClass ? \t\t\tstatic::class : \t\t\t$controllerClass;  \t\t\/\/ e.g. $controllerClass = Example\/Theme\/Main\/Example_Theme_Main_C \t\t$resourceInfo = [ \t\t\t'resourceName'         =&gt; '',\/\/ e.g. example--theme--main \t\t\t'relativePath'         =&gt; '',\/\/ e.g. Example\/Theme\/Main \t\t\t'relativeResourcePath' =&gt; '', \/\/ e.g. Example\/Theme\/Main\/example--theme--main \t\t];  \t\t$controllerSuffix = Settings::$ControllerSuffix;  \t\t\/\/  e.g. Example\/Theme\/Main\/Example_Theme_Main \t\t$relativeControllerNamespace = $settings-&gt;getBlocksDirNamespace() ? \t\t\tstr_replace( $settings-&gt;getBlocksDirNamespace() . '\\\\', '', $controllerClass ) : \t\t\t$controllerClass; \t\t$relativeControllerNamespace = substr( $relativeControllerNamespace, 0, mb_strlen( $relativeControllerNamespace ) - mb_strlen( $controllerSuffix ) );  \t\t\/\/ e.g. Example_Theme_Main \t\t$phpBlockName = explode( '\\\\', $relativeControllerNamespace ); \t\t$phpBlockName = $phpBlockName[ count( $phpBlockName ) - 1 ];  \t\t\/\/ e.g. example--theme--main (from Example_Theme_Main) \t\t$blockNameParts    = preg_split( '\/(?=[A-Z])\/', $phpBlockName, - 1, PREG_SPLIT_NO_EMPTY ); \t\t$blockResourceName = []; \t\tforeach ( $blockNameParts as $blockNamePart ) { \t\t\t$blockResourceName[] = strtolower( $blockNamePart ); \t\t} \t\t$blockResourceName = implode( '-', $blockResourceName ); \t\t$blockResourceName = str_replace( '_', '-', $blockResourceName );  \t\t\/\/ e.g. Example\/Theme\/Main \t\t$relativePath = explode( '\\\\', $relativeControllerNamespace ); \t\t$relativePath = array_slice( $relativePath, 0, count( $relativePath ) - 1 ); \t\t$relativePath = implode( DIRECTORY_SEPARATOR, $relativePath );  \t\t$resourceInfo['resourceName']         = $blockResourceName; \t\t$resourceInfo['relativePath']         = $relativePath; \t\t$resourceInfo['relativeResourcePath'] = $relativePath . DIRECTORY_SEPARATOR . $blockResourceName;  \t\treturn $resourceInfo;  \t}  \t\/\/ can be overridden if Controller doesn't have own twig (uses parents) \tpublic static function GetPathToTwigTemplate( Settings $settings, string $controllerClass = '' ): string { \t\treturn self::GetResourceInfo( $settings, $controllerClass )['relativeResourcePath'] . $settings-&gt;getTwigExtension(); \t}  \t\/\/ can be overridden if Controller doesn't have own model (uses parents) \tpublic static function GetModelClass(): string {  \t\t$controllerClass = static::class; \t\t$modelClass      = rtrim( $controllerClass, Settings::$ControllerSuffix );  \t\treturn ( $modelClass !== $controllerClass &amp;&amp; \t\t         class_exists( $modelClass, true ) &amp;&amp; \t\t         is_subclass_of( $modelClass, MODEL::class ) ? \t\t\t$modelClass : \t\t\t'' ); \t}  \tpublic static function OnLoad() {  \t}  \tfinal public function setModel( MODEL $model ): void { \t\t$this-&gt;_model = $model; \t}  \tprivate function _getControllerField( string $fieldName ): ?CONTROLLER {  \t\t$controller = null; \t\t$fieldsInfo = $this-&gt;_getFieldsInfo();  \t\tif ( key_exists( $fieldName, $fieldsInfo ) ) {  \t\t\t$controller = $this-&gt;{$fieldName};  \t\t\t\/\/ prevent possible recursion by a mistake (if someone will create a field with self) \t\t\t\/\/ using static for children support \t\t\t$controller = ( $controller &amp;&amp; \t\t\t                $controller instanceof CONTROLLER || \t\t\t                get_class( $controller ) !== static::class ) ? \t\t\t\t$controller : \t\t\t\tnull;  \t\t}  \t\treturn $controller;  \t}  \tpublic function getTemplateArgs( Settings $settings ): array {  \t\t$modelFields  = $this-&gt;_model ? \t\t\t$this-&gt;_model-&gt;getFields() : \t\t\t[]; \t\t$templateArgs = [];  \t\tforeach ( $modelFields as $modelFieldName =&gt; $modelFieldValue ) {  \t\t\t$templateFieldName = ltrim( $modelFieldName, '_' );  \t\t\tif ( ! $modelFieldValue instanceof MODEL ) {  \t\t\t\t$templateArgs[ $templateFieldName ] = $modelFieldValue;  \t\t\t\tcontinue; \t\t\t}  \t\t\t$modelFieldController = $this-&gt;_getControllerField( $modelFieldName ); \t\t\t$modelFieldArgs       = []; \t\t\t$externalFieldArgs    = $this-&gt;__external[ $modelFieldName ] ?? [];  \t\t\tif ( $modelFieldController ) {  \t\t\t\t$modelFieldController-&gt;setModel( $modelFieldValue ); \t\t\t\t$modelFieldArgs = $modelFieldController-&gt;getTemplateArgs( $settings );  \t\t\t}  \t\t\t$templateArgs[ $templateFieldName ] = HELPER::ArrayMergeRecursive( $modelFieldArgs, $externalFieldArgs );  \t\t}  \t\t\/\/ using static for children support \t\treturn array_merge( $templateArgs, [ \t\t\tself::TEMPLATE_KEY__TEMPLATE  =&gt; static::GetPathToTwigTemplate( $settings ), \t\t\tself::TEMPLATE_KEY__IS_LOADED =&gt; ( $this-&gt;_model &amp;&amp; $this-&gt;_model-&gt;isLoaded() ), \t\t] ); \t}  \tpublic function getDependencies( string $sourceClass = '' ): array {  \t\t$dependencyClasses = []; \t\t$controllerFields  = $this-&gt;_getFieldsInfo();  \t\tforeach ( $controllerFields as $fieldName =&gt; $fieldType ) {  \t\t\t$dependencyController = $this-&gt;_getControllerField( $fieldName );  \t\t\tif ( ! $dependencyController ) { \t\t\t\tcontinue; \t\t\t}  \t\t\t$dependencyClass = get_class( $dependencyController );  \t\t\t\/\/ 1. prevent the possible permanent recursion \t\t\t\/\/ 2. add only unique elements, because several fields can have the same type \t\t\tif ( ( $sourceClass &amp;&amp; $dependencyClass === $sourceClass ) || \t\t\t     in_array( $dependencyClass, $dependencyClasses, true ) ) { \t\t\t\tcontinue; \t\t\t}  \t\t\t\/\/ used static for child support \t\t\t$subDependencies = $dependencyController-&gt;getDependencies( static::class ); \t\t\t\/\/ only unique elements \t\t\t$subDependencies = array_diff( $subDependencies, $dependencyClasses );  \t\t\t\/\/ sub dependencies are before the main dependency \t\t\t$dependencyClasses = array_merge( $dependencyClasses, $subDependencies, [ $dependencyClass, ] );  \t\t}  \t\treturn $dependencyClasses; \t}  \t\/\/ Can be overridden for declare a target model class and provide an IDE support \tpublic function getModel(): ?MODEL { \t\treturn $this-&gt;_model; \t}  \tprivate function _autoInitModel() {  \t\tif ( $this-&gt;_model ) { \t\t\treturn; \t\t}  \t\t$modelClass = static::GetModelClass();  \t\ttry { \t\t\t$this-&gt;_model = $modelClass ? \t\t\t\tnew $modelClass() : \t\t\t\t$this-&gt;_model; \t\t} catch ( Exception $ex ) { \t\t\t$this-&gt;_model = null; \t\t}  \t}  } <\/code><\/pre>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>CONTROLLERTest.php<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php  declare( strict_types=1 );  namespace LightSource\\FrontBlocksFramework\\Tests\\unit;  use Codeception\\Test\\Unit; use LightSource\\FrontBlocksFramework\\{ \tCONTROLLER, \tMODEL, \tSettings };  class CONTROLLERTest extends Unit {  \tprivate function _getModel( array $fields, bool $isLoaded = false ): MODEL {  \t\treturn new class ( $fields, $isLoaded ) extends MODEL {  \t\t\tprivate array $_fields;  \t\t\tpublic function __construct( array $fields, bool $isLoaded ) {  \t\t\t\tparent::__construct();  \t\t\t\t$this-&gt;_fields = $fields;  \t\t\t\tif ( $isLoaded ) { \t\t\t\t\t$this-&gt;_load(); \t\t\t\t}  \t\t\t}  \t\t\tpublic function getFields(): array { \t\t\t\treturn $this-&gt;_fields; \t\t\t}  \t\t};  \t}  \tprivate function _getController( ?MODEL $model ): CONTROLLER { \t\treturn new class ( $model ) extends CONTROLLER {  \t\t\tpublic function __construct( ?MODEL $model = null ) { \t\t\t\tparent::__construct( $model ); \t\t\t}  \t\t}; \t}  \tprivate function _getTemplateArgsWithoutAdditional( array $templateArgs ) {  \t\t$templateArgs = array_diff_key( $templateArgs, [ \t\t\tCONTROLLER::TEMPLATE_KEY__TEMPLATE  =&gt; '', \t\t\tCONTROLLER::TEMPLATE_KEY__IS_LOADED =&gt; '', \t\t] ); \t\tforeach ( $templateArgs as $templateKey =&gt; $templateValue ) {  \t\t\tif ( ! is_array( $templateValue ) ) { \t\t\t\tcontinue; \t\t\t}  \t\t\t$templateArgs[ $templateKey ] = $this-&gt;_getTemplateArgsWithoutAdditional( $templateValue );  \t\t}  \t\treturn $templateArgs; \t}  \t\/\/\/\/  \tpublic function testGetResourceInfoWithoutCamelCaseInBlockName() {  \t\t$settings = new Settings(); \t\t$settings-&gt;setControllerSuffix( '_C' ); \t\t$settings-&gt;setBlocksDirNamespace( 'Namespace' );  \t\t$this-&gt;assertEquals( [ \t\t\t'resourceName'         =&gt; 'block', \t\t\t'relativePath'         =&gt; 'Block', \t\t\t'relativeResourcePath' =&gt; 'Block\/block', \t\t], CONTROLLER::GetResourceInfo( $settings, 'Namespace\\\\Block\\\\Block_C' ) );  \t}  \tpublic function testGetResourceInfoWithCamelCaseInBlockName() {  \t\t$settings = new Settings(); \t\t$settings-&gt;setControllerSuffix( '_C' ); \t\t$settings-&gt;setBlocksDirNamespace( 'Namespace' );  \t\t$this-&gt;assertEquals( [ \t\t\t'resourceName'         =&gt; 'block-name', \t\t\t'relativePath'         =&gt; 'BlockName', \t\t\t'relativeResourcePath' =&gt; 'BlockName\/block-name', \t\t], CONTROLLER::GetResourceInfo( $settings, 'Namespace\\\\BlockName\\\\BlockName_C' ) );  \t}  \tpublic function testGetResourceInfoWithoutCamelCaseInTheme() {  \t\t$settings = new Settings(); \t\t$settings-&gt;setControllerSuffix( '_C' ); \t\t$settings-&gt;setBlocksDirNamespace( 'Namespace' );  \t\t$this-&gt;assertEquals( [ \t\t\t'resourceName'         =&gt; 'block--theme--main', \t\t\t'relativePath'         =&gt; 'Block\/Theme\/Main', \t\t\t'relativeResourcePath' =&gt; 'Block\/Theme\/Main\/block--theme--main', \t\t], CONTROLLER::GetResourceInfo( $settings, 'Namespace\\\\Block\\\\Theme\\\\Main\\\\Block_Theme_Main_C' ) );  \t}  \tpublic function testGetResourceInfoWithCamelCaseInTheme() {  \t\t$settings = new Settings(); \t\t$settings-&gt;setControllerSuffix( '_C' ); \t\t$settings-&gt;setBlocksDirNamespace( 'Namespace' );  \t\t$this-&gt;assertEquals( [ \t\t\t'resourceName'         =&gt; 'block--theme--just-main', \t\t\t'relativePath'         =&gt; 'Block\/Theme\/JustMain', \t\t\t'relativeResourcePath' =&gt; 'Block\/Theme\/JustMain\/block--theme--just-main', \t\t], CONTROLLER::GetResourceInfo( $settings, 'Namespace\\\\Block\\\\Theme\\\\JustMain\\\\Block_Theme_JustMain_C' ) );  \t}  \t\/\/\/\/  \tpublic function testGetTemplateArgsWhenModelContainsBuiltInTypes() {  \t\t$settings   = new Settings(); \t\t$model      = $this-&gt;_getModel( [ \t\t\t'stringVariable' =&gt; 'just string', \t\t] ); \t\t$controller = $this-&gt;_getController( $model );  \t\t$this-&gt;assertEquals( [ \t\t\t'stringVariable' =&gt; 'just string', \t\t], $this-&gt;_getTemplateArgsWithoutAdditional( $controller-&gt;getTemplateArgs( $settings ) ) );  \t}  \tpublic function testGetTemplateArgsWhenModelContainsAnotherModel() {  \t\t$settings = new Settings();  \t\t$modelA              = $this-&gt;_getModel( [ \t\t\t'_modelA' =&gt; 'just string from model a', \t\t] ); \t\t$modelB              = $this-&gt;_getModel( [ \t\t\t'_modelA' =&gt; $modelA, \t\t\t'_modelB' =&gt; 'just string from model b', \t\t] ); \t\t$controllerForModelA = $this-&gt;_getController( null ); \t\t$controllerForModelB = new class ( $modelB, $controllerForModelA ) extends CONTROLLER {  \t\t\tprotected $_modelA;  \t\t\tpublic function __construct( ?MODEL $model = null, $controllerForModelA ) {  \t\t\t\tparent::__construct( $model );  \t\t\t\t$this-&gt;_modelA = $controllerForModelA;  \t\t\t}  \t\t};  \t\t$this-&gt;assertEquals( [ \t\t\t'modelA' =&gt; [ \t\t\t\t'modelA' =&gt; 'just string from model a', \t\t\t], \t\t\t'modelB' =&gt; 'just string from model b', \t\t], $this-&gt;_getTemplateArgsWithoutAdditional( $controllerForModelB-&gt;getTemplateArgs( $settings ) ) );  \t}  \tpublic function testGetTemplateArgsWhenControllerContainsExternalArgs() {  \t\t$settings = new Settings();  \t\t$modelA              = $this-&gt;_getModel( [ \t\t\t'_additionalField' =&gt; '', \t\t\t'_modelA'          =&gt; 'just string from model a', \t\t] ); \t\t$modelB              = $this-&gt;_getModel( [ \t\t\t'_modelA' =&gt; $modelA, \t\t\t'_modelB' =&gt; 'just string from model b', \t\t] ); \t\t$controllerForModelA = $this-&gt;_getController( null ); \t\t$controllerForModelB = new class ( $modelB, $controllerForModelA ) extends CONTROLLER {  \t\t\tprotected $_modelA;  \t\t\tpublic function __construct( ?MODEL $model = null, $controllerForModelA ) {  \t\t\t\tparent::__construct( $model );  \t\t\t\t$this-&gt;_modelA               = $controllerForModelA; \t\t\t\t$this-&gt;__external['_modelA'] = [ \t\t\t\t\t'additionalField' =&gt; 'additionalValue', \t\t\t\t];  \t\t\t}  \t\t};  \t\t$this-&gt;assertEquals( [ \t\t\t'modelA' =&gt; [ \t\t\t\t'additionalField' =&gt; 'additionalValue', \t\t\t\t'modelA'          =&gt; 'just string from model a', \t\t\t], \t\t\t'modelB' =&gt; 'just string from model b', \t\t], $this-&gt;_getTemplateArgsWithoutAdditional( $controllerForModelB-&gt;getTemplateArgs( $settings ) ) );  \t}  \tpublic function testGetTemplateArgsContainsAdditionalFields() {  \t\t$settings   = new Settings(); \t\t$model      = $this-&gt;_getModel( [] ); \t\t$controller = $this-&gt;_getController( $model );  \t\t$this-&gt;assertEquals( [ \t\t\tCONTROLLER::TEMPLATE_KEY__TEMPLATE, \t\t\tCONTROLLER::TEMPLATE_KEY__IS_LOADED, \t\t], array_keys( $controller-&gt;getTemplateArgs( $settings ) ) );  \t}  \tpublic function testGetTemplateArgsWhenAdditionalIsLoadedIsFalse() {  \t\t$settings   = new Settings(); \t\t$model      = $this-&gt;_getModel( [] ); \t\t$controller = $this-&gt;_getController( $model );  \t\t$actual = array_intersect_key( $controller-&gt;getTemplateArgs( $settings ), [ CONTROLLER::TEMPLATE_KEY__IS_LOADED =&gt; '', ] );  \t\t$this-&gt;assertEquals( [ CONTROLLER::TEMPLATE_KEY__IS_LOADED =&gt; false, ], $actual );  \t}  \tpublic function testGetTemplateArgsWhenAdditionalIsLoadedIsTrue() {  \t\t$settings   = new Settings(); \t\t$model      = $this-&gt;_getModel( [], true ); \t\t$controller = $this-&gt;_getController( $model );  \t\t$actual = array_intersect_key( $controller-&gt;getTemplateArgs( $settings ), [ CONTROLLER::TEMPLATE_KEY__IS_LOADED =&gt; '', ] );  \t\t$this-&gt;assertEquals( [ CONTROLLER::TEMPLATE_KEY__IS_LOADED =&gt; true, ], $actual );  \t}  \tpublic function testGetTemplateArgsAdditionalTemplateIsRight() {  \t\t$settings   = new Settings(); \t\t$model      = $this-&gt;_getModel( [] ); \t\t$controller = $this-&gt;_getController( $model );  \t\t$actual = array_intersect_key( $controller-&gt;getTemplateArgs( $settings ), [ CONTROLLER::TEMPLATE_KEY__TEMPLATE =&gt; '', ] );  \t\t$this-&gt;assertEquals( [ \t\t\tCONTROLLER::TEMPLATE_KEY__TEMPLATE =&gt; $controller::GetPathToTwigTemplate( $settings ), \t\t], $actual ); \t}  \t\/\/\/\/  \tpublic function testGetDependencies() {  \t\t$controllerA = $this-&gt;_getController( null );  \t\t$controllerB = new class ( null, $controllerA ) extends CONTROLLER {  \t\t\tprotected $_controllerA;  \t\t\tpublic function __construct( ?MODEL $model = null, $controllerA ) {  \t\t\t\tparent::__construct( $model );  \t\t\t\t$this-&gt;_controllerA = $controllerA;  \t\t\t}  \t\t};  \t\t$this-&gt;assertEquals( [ \t\t\tget_class( $controllerA ), \t\t], $controllerB-&gt;getDependencies() );  \t}  \tpublic function testGetDependenciesWithSubDependencies() {  \t\t$controllerA = new class extends CONTROLLER {  \t\t\tpublic function getDependencies( string $sourceClass = '' ): array { \t\t\t\treturn [ \t\t\t\t\t'A', \t\t\t\t]; \t\t\t}  \t\t};  \t\t$controllerB = new class ( null, $controllerA ) extends CONTROLLER {  \t\t\tprotected $_controllerA;  \t\t\tpublic function __construct( ?MODEL $model = null, $controllerA ) {  \t\t\t\tparent::__construct( $model );  \t\t\t\t$this-&gt;_controllerA = $controllerA;  \t\t\t}  \t\t};  \t\t$this-&gt;assertEquals( [ \t\t\t'A', \t\t\tget_class( $controllerA ), \t\t], $controllerB-&gt;getDependencies() );  \t}  \tpublic function testGetDependenciesWithSubDependenciesRecursively() {  \t\t$controllerA = new class extends CONTROLLER {  \t\t\tpublic function getDependencies( string $sourceClass = '' ): array { \t\t\t\treturn [ \t\t\t\t\t'A', \t\t\t\t]; \t\t\t}  \t\t};  \t\t$controllerB = new class ( null, $controllerA ) extends CONTROLLER {  \t\t\tprotected $_controllerA;  \t\t\tpublic function __construct( ?MODEL $model = null, $controllerA ) {  \t\t\t\tparent::__construct( $model );  \t\t\t\t$this-&gt;_controllerA = $controllerA;  \t\t\t}  \t\t};  \t\t$controllerC = new class ( null, $controllerB ) extends CONTROLLER {  \t\t\tprotected $_controllerB;  \t\t\tpublic function __construct( ?MODEL $model = null, $controllerB ) {  \t\t\t\tparent::__construct( $model );  \t\t\t\t$this-&gt;_controllerB = $controllerB;  \t\t\t}  \t\t};  \t\t$this-&gt;assertEquals( [ \t\t\t'A', \t\t\tget_class( $controllerA ), \t\t\tget_class( $controllerB ), \t\t], $controllerC-&gt;getDependencies() );  \t}  \tpublic function testGetDependenciesWithSubDependenciesInOrderWhenSubBeforeMainDependency() {  \t\t$controllerA = new class extends CONTROLLER {  \t\t\tpublic function getDependencies( string $sourceClass = '' ): array { \t\t\t\treturn [ \t\t\t\t\t'A', \t\t\t\t]; \t\t\t}  \t\t};  \t\t$controllerB = new class ( null, $controllerA ) extends CONTROLLER {  \t\t\tprotected $_controllerA;  \t\t\tpublic function __construct( ?MODEL $model = null, $controllerA ) {  \t\t\t\tparent::__construct( $model );  \t\t\t\t$this-&gt;_controllerA = $controllerA;  \t\t\t}  \t\t};  \t\t$this-&gt;assertEquals( [ \t\t\t'A', \t\t\tget_class( $controllerA ), \t\t], $controllerB-&gt;getDependencies() );  \t}  \tpublic function testGetDependenciesWithSubDependenciesWhenBlocksAreDependentFromEachOther() {  \t\t$controllerA = new class extends CONTROLLER {  \t\t\tprotected $_controllerB;  \t\t\tpublic function setControllerB( $controllerB ) { \t\t\t\t$this-&gt;_controllerB = $controllerB; \t\t\t}  \t\t};  \t\t$controllerB = new class ( null, $controllerA ) extends CONTROLLER {  \t\t\tprotected $_controllerA;  \t\t\tpublic function __construct( ?MODEL $model = null, $controllerA ) {  \t\t\t\tparent::__construct( $model );  \t\t\t\t$this-&gt;_controllerA = $controllerA;  \t\t\t}  \t\t};  \t\t$controllerA-&gt;setControllerB( $controllerB );  \t\t$this-&gt;assertEquals( [ \t\t\tget_class( $controllerA ), \t\t], $controllerB-&gt;getDependencies() );  \t}  \tpublic function testGetDependenciesWithoutDuplicatesWhenSeveralWithOneType() {  \t\t$controllerA = $this-&gt;_getController( null );  \t\t$controllerB = new class ( null, $controllerA ) extends CONTROLLER {  \t\t\tprotected $_controllerA; \t\t\tprotected $_controllerAA; \t\t\tprotected $_controllerAAA;  \t\t\tpublic function __construct( ?MODEL $model = null, $controllerA ) {  \t\t\t\tparent::__construct( $model );  \t\t\t\t$this-&gt;_controllerA   = $controllerA; \t\t\t\t$this-&gt;_controllerAA  = $controllerA; \t\t\t\t$this-&gt;_controllerAAA = $controllerA;  \t\t\t}  \t\t};  \t\t$this-&gt;assertEquals( [ \t\t\tget_class( $controllerA ), \t\t], $controllerB-&gt;getDependencies() );  \t}  \t\/\/\/\/  \tpublic function testAutoInitModel() {  \t\t$modelClass      = str_replace( [ '::', '\\\\' ], '_', __METHOD__ ); \t\t$controllerClass = $modelClass . Settings::$ControllerSuffix; \t\teval( 'class ' . $modelClass . ' extends ' . MODEL::class . ' {}' ); \t\teval( 'class ' . $controllerClass . ' extends ' . CONTROLLER::class . ' {}' ); \t\t$controller = new $controllerClass();  \t\t$actualModelClass = $controller-&gt;getModel() ? \t\t\tget_class( $controller-&gt;getModel() ) : \t\t\t'';  \t\t$this-&gt;assertEquals( $modelClass, $actualModelClass );  \t}  \tpublic function testAutoInitModelWhenModelHasWrongClass() {  \t\t$modelClass      = str_replace( [ '::', '\\\\' ], '_', __METHOD__ ); \t\t$controllerClass = $modelClass . Settings::$ControllerSuffix; \t\teval( 'class ' . $modelClass . ' {}' ); \t\teval( 'class ' . $controllerClass . ' extends ' . CONTROLLER::class . ' {}' ); \t\t$controller = new $controllerClass();  \t\t$this-&gt;assertEquals( null, $controller-&gt;getModel() );  \t}  } <\/code><\/pre>\n<\/div>\n<\/details>\n<p><strong>Settings<\/strong><\/p>\n<p>\u0412\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441, \u0434\u0443\u043c\u0430\u044e \u0447\u0442\u043e \u043d\u0435 \u043d\u0443\u0436\u0434\u0430\u0435\u0442\u0441\u044f \u0432 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u0445<\/p>\n<details class=\"spoiler\">\n<summary>Settings.php<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php  declare( strict_types=1 );  namespace LightSource\\FrontBlocksFramework;  class Settings {  \tpublic static string $ControllerSuffix = '_C';  \tprivate string $_blocksDirPath; \tprivate string $_blocksDirNamespace; \tprivate array $_twigArgs; \tprivate string $_twigExtension; \tprivate $_errorCallback;  \tpublic function __construct() {  \t\t$this-&gt;_blocksDirPath      = ''; \t\t$this-&gt;_blocksDirNamespace = ''; \t\t$this-&gt;_twigArgs           = [ \t\t\t\/\/ will generate exception if a var doesn't exist instead of replace to NULL \t\t\t'strict_variables' =&gt; true, \t\t\t\/\/ disable autoescape to prevent break data \t\t\t'autoescape'       =&gt; false, \t\t]; \t\t$this-&gt;_twigExtension      = '.twig'; \t\t$this-&gt;_errorCallback      = null;  \t}  \tpublic function setBlocksDirPath( string $blocksDirPath ): void { \t\t$this-&gt;_blocksDirPath = $blocksDirPath; \t}  \tpublic function setBlocksDirNamespace( string $blocksDirNamespace ): void { \t\t$this-&gt;_blocksDirNamespace = $blocksDirNamespace; \t}  \tpublic function setTwigArgs( array $twigArgs ): void { \t\t$this-&gt;_twigArgs = array_merge( $this-&gt;_twigArgs, $twigArgs ); \t}  \tpublic function setErrorCallback( ?callable $errorCallback ): void { \t\t$this-&gt;_errorCallback = $errorCallback; \t}  \tpublic function setTwigExtension( string $twigExtension ): void { \t\t$this-&gt;_twigExtension = $twigExtension; \t}  \tpublic function setControllerSuffix( string $controllerSuffix ): void { \t\t$this-&gt;_controllerSuffix = $controllerSuffix; \t}  \tpublic function getBlocksDirPath(): string { \t\treturn $this-&gt;_blocksDirPath; \t}  \tpublic function getBlocksDirNamespace(): string { \t\treturn $this-&gt;_blocksDirNamespace; \t}  \tpublic function getTwigArgs(): array { \t\treturn $this-&gt;_twigArgs; \t}  \tpublic function getTwigExtension(): string { \t\treturn $this-&gt;_twigExtension; \t}  \tpublic function callErrorCallback( array $errors ): void {  \t\tif ( ! is_callable( $this-&gt;_errorCallback ) ) { \t\t\treturn; \t\t}  \t\tcall_user_func_array( $this-&gt;_errorCallback, [ $errors, ] );  \t}  } <\/code><\/pre>\n<\/div>\n<\/details>\n<p><strong>Twig<\/strong><\/p>\n<p>\u0422\u0430\u043a\u0436\u0435 \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441, \u043b\u0438\u0448\u044c \u0443\u0442\u043e\u0447\u043d\u044e \u0447\u0442\u043e \u043c\u044b \u0440\u0430\u0441\u0448\u0438\u0440\u0438\u043b\u0438 twig \u0441\u0432\u043e\u0435\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0435\u0439 _include (\u043a\u043e\u0442\u043e\u0440\u0430\u044f \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u0431\u0435\u0440\u0442\u043a\u043e\u0439 \u0434\u043b\u044f \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u043e\u0433\u043e \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u043d\u0430\u0448\u0438 \u043f\u043e\u043b\u044f _isLoaded \u0438 _template \u0438\u0437 \u043c\u0435\u0442\u043e\u0434\u0430 CONROLLER-&gt;getTemplateArgs \u0432\u044b\u0448\u0435) \u0438 \u0444\u0438\u043b\u044c\u0442\u0440 _merge (\u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0442\u043b\u0438\u0447\u0430\u0435\u0442\u0441\u044f \u0442\u0435\u043c, \u0447\u0442\u043e \u0440\u0435\u043a\u0443\u0440\u0441\u0438\u0432\u043d\u043e \u0441\u043b\u0438\u0432\u0430\u0435\u0442 \u043c\u0430\u0441\u0441\u0438\u0432\u044b).<\/p>\n<details class=\"spoiler\">\n<summary>Twig.php<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php  declare( strict_types=1 );  namespace LightSource\\FrontBlocksFramework;  use Exception; use Twig\\Environment; use Twig\\Loader\\FilesystemLoader; use Twig\\Loader\\LoaderInterface; use Twig\\TwigFilter; use Twig\\TwigFunction;  class Twig {  \tprivate ?LoaderInterface $_twigLoader; \tprivate ?Environment $_twigEnvironment; \tprivate Settings $_settings;  \tpublic function __construct( Settings $settings, ?LoaderInterface $twigLoader = null ) {  \t\t$this-&gt;_twigEnvironment = null; \t\t$this-&gt;_settings        = $settings; \t\t$this-&gt;_twigLoader      = $twigLoader;  \t\t$this-&gt;_init();  \t}  \t\/\/ e.g for extend a twig with adding a new filter \tpublic function getEnvironment(): ?Environment { \t\treturn $this-&gt;_twigEnvironment; \t}  \tprivate function _extendTwig(): void {  \t\t$this-&gt;_twigEnvironment-&gt;addFilter( new TwigFilter( '_merge', function ( $source, $additional ) { \t\t\treturn HELPER::ArrayMergeRecursive( $source, $additional ); \t\t} ) ); \t\t$this-&gt;_twigEnvironment-&gt;addFunction( new TwigFunction( '_include', function ( $block, $args = [] ) {  \t\t\t$block = HELPER::ArrayMergeRecursive( $block, $args );  \t\t\treturn $block[ CONTROLLER::TEMPLATE_KEY__IS_LOADED ] ? \t\t\t\t$this-&gt;render( $block[ CONTROLLER::TEMPLATE_KEY__TEMPLATE ], $block ) : \t\t\t\t''; \t\t} ) );  \t}  \tprivate function _init(): void {  \t\ttry {  \t\t\t$this-&gt;_twigLoader      = ! $this-&gt;_twigLoader ? \t\t\t\tnew FilesystemLoader( $this-&gt;_settings-&gt;getBlocksDirPath() ) : \t\t\t\t$this-&gt;_twigLoader; \t\t\t$this-&gt;_twigEnvironment = new Environment( $this-&gt;_twigLoader, $this-&gt;_settings-&gt;getTwigArgs() );  \t\t} catch ( Exception $ex ) {  \t\t\t$this-&gt;_twigEnvironment = null;  \t\t\t$this-&gt;_settings-&gt;callErrorCallback( [ \t\t\t\t'message' =&gt; $ex-&gt;getMessage(), \t\t\t\t'file'    =&gt; $ex-&gt;getFile(), \t\t\t\t'line'    =&gt; $ex-&gt;getLine(), \t\t\t\t'trace'   =&gt; $ex-&gt;getTraceAsString(), \t\t\t] );  \t\t\treturn;  \t\t}  \t\t$this-&gt;_extendTwig();  \t}  \tpublic function render( string $template, array $args = [], bool $isPrint = false ): string {  \t\t$html = '';  \t\t\/\/ twig isn't loaded \t\tif ( is_null( $this-&gt;_twigEnvironment ) ) { \t\t\treturn $html; \t\t}  \t\ttry { \t\t\t\/\/ will generate ean exception if a template doesn't exist OR broken \t\t\t\/\/ also if a var doesn't exist (if using a 'strict_variables' flag, see Twig_Environment-&gt;__construct) \t\t\t$html .= $this-&gt;_twigEnvironment-&gt;render( $template, $args ); \t\t} catch ( Exception $ex ) {  \t\t\t$html = '';  \t\t\t$this-&gt;_settings-&gt;callErrorCallback( [ \t\t\t\t'message'  =&gt; $ex-&gt;getMessage(), \t\t\t\t'file'     =&gt; $ex-&gt;getFile(), \t\t\t\t'line'     =&gt; $ex-&gt;getLine(), \t\t\t\t'trace'    =&gt; $ex-&gt;getTraceAsString(), \t\t\t\t'template' =&gt; $template, \t\t\t] );  \t\t}  \t\tif ( $isPrint ) { \t\t\techo $html; \t\t}  \t\treturn $html;  \t}  } <\/code><\/pre>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>TwigTest.php<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php  declare( strict_types=1 );  namespace LightSource\\FrontBlocksFramework\\Tests\\unit;  use Codeception\\Test\\Unit; use Exception; use LightSource\\FrontBlocksFramework\\CONTROLLER; use LightSource\\FrontBlocksFramework\\Settings; use LightSource\\FrontBlocksFramework\\Twig; use Twig\\Loader\\ArrayLoader;  class TwigTest extends Unit {  \tprivate function _renderBlock( array $blocks, string $renderBlock, array $renderArgs = [] ): string {  \t\t$twigLoader = new ArrayLoader( $blocks ); \t\t$settings   = new Settings();  \t\t$twig    = new Twig( $settings, $twigLoader ); \t\t$content = '';  \t\ttry {  \t\t\t$content = $twig-&gt;render( $renderBlock, $renderArgs );  \t\t} catch ( Exception $ex ) { \t\t\t$this-&gt;fail( 'Twig render exception, ' . $ex-&gt;getMessage() ); \t\t}  \t\treturn $content; \t}  \tpublic function testExtendTwigIncludeFunctionWhenBlockIsLoaded() {  \t\t$blocks      = [ \t\t\t'block-a.twig' =&gt; '{{ _include(blockB) }}', \t\t\t'block-b.twig' =&gt; 'block-b content', \t\t]; \t\t$renderBlock = 'block-a.twig'; \t\t$renderArgs  = [ \t\t\t'blockB' =&gt; [ \t\t\t\tCONTROLLER::TEMPLATE_KEY__TEMPLATE  =&gt; 'block-b.twig', \t\t\t\tCONTROLLER::TEMPLATE_KEY__IS_LOADED =&gt; true, \t\t\t], \t\t];  \t\t$this-&gt;assertEquals( 'block-b content', $this-&gt;_renderBlock( $blocks, $renderBlock, $renderArgs ) );  \t}  \tpublic function testExtendTwigIncludeFunctionWhenBlockNotLoaded() {  \t\t$blocks      = [ \t\t\t'block-a.twig' =&gt; '{{ _include(blockB) }}', \t\t\t'block-b.twig' =&gt; 'block-b content', \t\t]; \t\t$renderBlock = 'block-a.twig'; \t\t$renderArgs  = [ \t\t\t'blockB' =&gt; [ \t\t\t\tCONTROLLER::TEMPLATE_KEY__TEMPLATE  =&gt; 'block-b.twig', \t\t\t\tCONTROLLER::TEMPLATE_KEY__IS_LOADED =&gt; false, \t\t\t], \t\t];  \t\t$this-&gt;assertEquals( '', $this-&gt;_renderBlock( $blocks, $renderBlock, $renderArgs ) );  \t}  \tpublic function testExtendTwigIncludeFunctionWhenArgsPassed() {  \t\t$blocks      = [ \t\t\t'block-a.twig' =&gt; '{{ _include(blockB, {classes:[\"test-class\",],}) }}', \t\t\t'block-b.twig' =&gt; '{{ classes|join(\" \") }}', \t\t]; \t\t$renderBlock = 'block-a.twig'; \t\t$renderArgs  = [ \t\t\t'blockB' =&gt; [ \t\t\t\tCONTROLLER::TEMPLATE_KEY__TEMPLATE  =&gt; 'block-b.twig', \t\t\t\tCONTROLLER::TEMPLATE_KEY__IS_LOADED =&gt; true, \t\t\t\t'classes'                           =&gt; [ 'own-class', ], \t\t\t], \t\t];  \t\t$this-&gt;assertEquals( 'own-class test-class', $this-&gt;_renderBlock( $blocks, $renderBlock, $renderArgs ) );  \t}  \tpublic function testExtendTwigMergeFilter() {  \t\t$blocks      = [ \t\t\t'block-a.twig' =&gt; '{{ {\"array\":[\"a\",],}|_merge({\"array\":[\"b\",],}).array|join(\" \") }}', \t\t]; \t\t$renderBlock = 'block-a.twig'; \t\t$renderArgs  = [];  \t\t$this-&gt;assertEquals( 'a b', $this-&gt;_renderBlock( $blocks, $renderBlock, $renderArgs ) );   \t}  } <\/code><\/pre>\n<\/div>\n<\/details>\n<p><strong>Blocks<\/strong><\/p>\n<p>\u042d\u0442\u043e \u043d\u0430\u0448 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u044e\u0449\u0438\u0439 \u043a\u043b\u0430\u0441\u0441.<\/p>\n<p>\u0421\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u043c\u0435\u0442\u043e\u0434 LoadAll \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442 \u0432\u0441\u0435 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u044b \u0438 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u043c\u0435\u0442\u043e\u0434 OnLoad \u0443 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430 (\u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u044d\u0442\u043e \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f, \u043a\u0430\u043a \u0431\u044b\u043b\u043e \u0443\u043a\u0430\u0437\u0430\u043d\u043e \u0432\u044b\u0448\u0435 \u044d\u0442\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u043b\u044f \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f \u0438 \u0432\u044b\u0445\u043e\u0434\u0438\u0442 \u0437\u0430 \u0440\u0430\u043c\u043a\u0438 \u0441\u0442\u0430\u0442\u044c\u0438).<\/p>\n<p>\u041c\u0435\u0442\u043e\u0434 renderBlock \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u043e\u0431\u044a\u0435\u043a\u0442 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430 \u0438 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442 \u0440\u0435\u043d\u0434\u0435\u0440 \u0431\u043b\u043e\u043a\u0430, \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u044f \u0432 twig \u0448\u0430\u0431\u043b\u043e\u043d \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u044b \u0438\u0437 \u043c\u0435\u0442\u043e\u0434\u0430 CONROLLER-&gt;getTemplateArgs \u0432\u044b\u0448\u0435. \u0422\u0430\u043a\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u043a\u043b\u0430\u0441\u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u043e\u0433\u043e \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430 \u0438 \u043a\u043b\u0430\u0441\u0441\u044b \u0432\u0441\u0435\u0445 \u0435\u0433\u043e \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u0432 \u0441\u043f\u0438\u0441\u043e\u043a \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0431\u043b\u043e\u043a\u043e\u0432, \u0447\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u043d\u0430\u043c \u0434\u0430\u043b\u0435\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0439 css \u0438 js.<\/p>\n<p>\u041d\u0443 \u0438 \u043d\u0430\u043a\u043e\u043d\u0435\u0446 \u043c\u0435\u0442\u043e\u0434 getUsedResources \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u0441\u043f\u0438\u0441\u043e\u043a \u0432\u044b\u0448\u0435 \u0438 \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u043c\u0435\u0442\u043e\u0434 CONTROLLER::GetResourceInfo \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0430\u043c \u043f\u043e\u0441\u043b\u0435 \u0440\u0435\u043d\u0434\u0435\u0440\u0430 \u0431\u043b\u043e\u043a\u043e\u0432 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0439 css \u0438 js \u043a\u043e\u0434, \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0435\u043d\u043d\u044b\u0439 \u0432 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u0439 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438, \u0442.\u0435. \u0441 \u0443\u0447\u0435\u0442\u043e\u043c \u0432\u0441\u0435\u0445 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439.\/<\/p>\n<details class=\"spoiler\">\n<summary>Blocks.php<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php  declare( strict_types=1 );  namespace LightSource\\FrontBlocksFramework;  class Blocks {  \tprivate array $_loadedControllerClasses; \tprivate array $_usedControllerClasses; \tprivate Settings $_settings; \tprivate Twig $_twig;  \tpublic function __construct( Settings $settings ) {  \t\t$this-&gt;_loadedControllerClasses = []; \t\t$this-&gt;_usedControllerClasses   = []; \t\t$this-&gt;_settings                = $settings; \t\t$this-&gt;_twig                    = new Twig( $settings );  \t}  \tfinal public function getLoadedControllerClasses(): array { \t\treturn $this-&gt;_loadedControllerClasses; \t}  \tfinal public function getUsedControllerClasses(): array { \t\treturn $this-&gt;_usedControllerClasses; \t}  \tfinal public function getSettings(): Settings { \t\treturn $this-&gt;_settings; \t}  \tfinal public function getTwig(): Twig { \t\treturn $this-&gt;_twig; \t}  \tfinal public function getUsedResources( string $extension, bool $isIncludeSource = false ): string {  \t\t$resourcesContent = '';  \t\tforeach ( $this-&gt;_usedControllerClasses as $usedControllerClass ) {  \t\t\t$getResourcesInfoCallback = [ $usedControllerClass, 'GetResourceInfo' ];  \t\t\tif ( ! is_callable( $getResourcesInfoCallback ) ) {  \t\t\t\t$this-&gt;_settings-&gt;callErrorCallback( [ \t\t\t\t\t'message' =&gt; \"Controller class doesn't exist\", \t\t\t\t\t'class'   =&gt; $usedControllerClass, \t\t\t\t] );  \t\t\t\tcontinue; \t\t\t}  \t\t\t$resourceInfo = call_user_func_array( $getResourcesInfoCallback, [ \t\t\t\t$this-&gt;_settings, \t\t\t] );  \t\t\t$pathToResourceFile = $this-&gt;_settings-&gt;getBlocksDirPath() . DIRECTORY_SEPARATOR . $resourceInfo['relativeResourcePath'] . $extension;  \t\t\tif ( ! is_file( $pathToResourceFile ) ) { \t\t\t\tcontinue; \t\t\t}  \t\t\t$resourcesContent .= $isIncludeSource ? \t\t\t\t\"\\n\/* \" . $resourceInfo['resourceName'] . \" *\/\\n\" : \t\t\t\t'';  \t\t\t$resourcesContent .= file_get_contents( $pathToResourceFile );  \t\t}  \t\treturn $resourcesContent; \t}  \tprivate function _loadController( string $phpClass, array $debugArgs ): bool {  \t\t$isLoaded = false;  \t\tif ( ! class_exists( $phpClass, true ) || \t\t     ! is_subclass_of( $phpClass, CONTROLLER::class ) ) {  \t\t\t$this-&gt;_settings-&gt;callErrorCallback( [ \t\t\t\t'message' =&gt; \"Class doesn't exist or doesn't child\", \t\t\t\t'args'    =&gt; $debugArgs, \t\t\t] );  \t\t\treturn $isLoaded; \t\t}  \t\tcall_user_func( [ $phpClass, 'OnLoad' ] );  \t\treturn true; \t}  \tprivate function _loadControllers( string $directory, string $namespace, array $controllerFileNames ): void {  \t\tforeach ( $controllerFileNames as $controllerFileName ) {  \t\t\t$phpFile   = implode( DIRECTORY_SEPARATOR, [ $directory, $controllerFileName ] ); \t\t\t$phpClass  = implode( '\\\\', [ $namespace, str_replace( '.php', '', $controllerFileName ), ] ); \t\t\t$debugArgs = [ \t\t\t\t'directory' =&gt; $directory, \t\t\t\t'namespace' =&gt; $namespace, \t\t\t\t'phpFile'   =&gt; $phpFile, \t\t\t\t'phpClass'  =&gt; $phpClass, \t\t\t];  \t\t\tif ( ! $this-&gt;_loadController( $phpClass, $debugArgs ) ) { \t\t\t\tcontinue; \t\t\t}  \t\t\t$this-&gt;_loadedControllerClasses[] = $phpClass;  \t\t}  \t}  \tprivate function _loadDirectory( string $directory, string $namespace ): void {  \t\t\/\/ exclude ., .. \t\t$fs = array_diff( scandir( $directory ), [ '.', '..' ] );  \t\t$controllerFilePreg = '\/' . Settings::$ControllerSuffix . '.php$\/';  \t\t$controllerFileNames = HELPER::ArrayFilter( $fs, function ( $f ) use ( $controllerFilePreg ) { \t\t\treturn ( 1 === preg_match( $controllerFilePreg, $f ) ); \t\t}, false ); \t\t$subDirectoryNames   = HELPER::ArrayFilter( $fs, function ( $f ) { \t\t\treturn false === strpos( $f, '.' ); \t\t}, false );  \t\tforeach ( $subDirectoryNames as $subDirectoryName ) {  \t\t\t$subDirectory = implode( DIRECTORY_SEPARATOR, [ $directory, $subDirectoryName ] ); \t\t\t$subNamespace = implode( '\\\\', [ $namespace, $subDirectoryName ] );  \t\t\t$this-&gt;_loadDirectory( $subDirectory, $subNamespace );  \t\t}  \t\t$this-&gt;_loadControllers( $directory, $namespace, $controllerFileNames );  \t}  \tfinal public function loadAll(): void {  \t\t$directory = $this-&gt;_settings-&gt;getBlocksDirPath(); \t\t$namespace = $this-&gt;_settings-&gt;getBlocksDirNamespace();  \t\t$this-&gt;_loadDirectory( $directory, $namespace );  \t}  \tfinal public function renderBlock( CONTROLLER $controller, array $args = [], bool $isPrint = false ): string {  \t\t$dependencies                 = array_merge( $controller-&gt;getDependencies(), [ get_class( $controller ), ] ); \t\t$newDependencies              = array_diff( $dependencies, $this-&gt;_usedControllerClasses ); \t\t$this-&gt;_usedControllerClasses = array_merge( $this-&gt;_usedControllerClasses, $newDependencies );  \t\t$templateArgs = $controller-&gt;getTemplateArgs( $this-&gt;_settings ); \t\t$templateArgs = HELPER::ArrayMergeRecursive( $templateArgs, $args );  \t\treturn $this-&gt;_twig-&gt;render( $templateArgs[ CONTROLLER::TEMPLATE_KEY__TEMPLATE ], $templateArgs, $isPrint ); \t}  } <\/code><\/pre>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>BlocksTest.php<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php  declare( strict_types=1 );  namespace LightSource\\FrontBlocksFramework\\Tests\\unit;  use Codeception\\Test\\Unit; use Exception; use LightSource\\FrontBlocksFramework\\Blocks; use LightSource\\FrontBlocksFramework\\CONTROLLER; use LightSource\\FrontBlocksFramework\\MODEL; use LightSource\\FrontBlocksFramework\\Settings; use LightSource\\FrontBlocksFramework\\Twig; use org\\bovigo\\vfs\\vfsStream; use org\\bovigo\\vfs\\vfsStreamDirectory;  class BlocksTest extends Unit {  \tprivate function _getBlocks( string $namespace, vfsStreamDirectory $rootDirectory, array $structure, array $usedControllerClasses = [] ): ?Blocks {  \t\tvfsStream::create( $structure, $rootDirectory );  \t\t$settings = new Settings(); \t\t$settings-&gt;setBlocksDirNamespace( $namespace ); \t\t$settings-&gt;setBlocksDirPath( $rootDirectory-&gt;url() );  \t\t$twig = $this-&gt;make( Twig::class, [ \t\t\t'render' =&gt; function ( string $template, array $args = [], bool $isPrint = false ): string { \t\t\t\treturn ''; \t\t\t}, \t\t] );  \t\ttry { \t\t\t$blocks = $this-&gt;make( Blocks::class, [ \t\t\t\t'_loadedControllerClasses' =&gt; [], \t\t\t\t'_usedControllerClasses'   =&gt; $usedControllerClasses, \t\t\t\t'_twig'                    =&gt; $twig, \t\t\t\t'_settings'                =&gt; $settings, \t\t\t] );  \t\t} catch ( Exception $ex ) { \t\t\t$this-&gt;fail( \"Can't make Blocks stub, \" . $ex-&gt;getMessage() ); \t\t}  \t\t$blocks-&gt;loadAll();  \t\treturn $blocks; \t}  \t\/\/ get a unique namespace depending on a test method to prevent affect other tests \tprivate function _getUniqueControllerNamespaceWithAutoloader( string $methodConstant, vfsStreamDirectory $rootDirectory ): string {  \t\t$namespace = str_replace( '::', '_', $methodConstant );  \t\tspl_autoload_register( function ( $class ) use ( $rootDirectory, $namespace ) {  \t\t\t$targetNamespace = $namespace . '\\\\'; \t\t\tif ( 0 !== strpos( $class, $targetNamespace ) ) { \t\t\t\treturn; \t\t\t}  \t\t\t$relativePathToFile = str_replace( $targetNamespace, '', $class ); \t\t\t$relativePathToFile = str_replace( '\\\\', '\/', $relativePathToFile );  \t\t\t$absPathToFile = $rootDirectory-&gt;url() . DIRECTORY_SEPARATOR . $relativePathToFile . '.php';  \t\t\tinclude_once $absPathToFile;  \t\t} );  \t\treturn $namespace; \t}  \t\/\/ get a unique directory name depending on a test method to prevent affect other tests \tprivate function _getUniqueDirectory( string $methodConstant ): vfsStreamDirectory {  \t\t$dirName = str_replace( [ ':', '\\\\' ], '_', $methodConstant );  \t\treturn vfsStream::setup( $dirName ); \t}  \tprivate function _getControllerClassFile( string $namespace, string $class ): string {  \t\t$vendorControllerClass = '\\LightSource\\FrontBlocksFramework\\CONTROLLER';  \t\treturn '&lt;?php namespace ' . $namespace . '; class ' . $class . ' extends ' . $vendorControllerClass . ' {}'; \t}  \tprivate function _getController( array $dependencies = [] ) { \t\treturn new class ( null, $dependencies ) extends CONTROLLER {  \t\t\tprivate array $_dependencies;  \t\t\tpublic function __construct( ?MODEL $model = null, array $dependencies ) {  \t\t\t\tparent::__construct( $model ); \t\t\t\t$this-&gt;_dependencies = $dependencies;  \t\t\t}  \t\t\tfunction getDependencies( string $sourceClass = '' ): array { \t\t\t\treturn $this-&gt;_dependencies; \t\t\t}  \t\t\tfunction getTemplateArgs( Settings $settings ): array { \t\t\t\treturn [ \t\t\t\t\tCONTROLLER::TEMPLATE_KEY__TEMPLATE =&gt; '', \t\t\t\t]; \t\t\t}   \t\t}; \t}  \t\/\/\/\/  \tpublic function testLoadAllControllersWithPrefix() {  \t\t\/\/ fixme \t\t$rootDirectory = $this-&gt;_getUniqueDirectory( __METHOD__ ); \t\t$namespace     = $this-&gt;_getUniqueControllerNamespaceWithAutoloader( __METHOD__, $rootDirectory ); \t\t$blocks        = $this-&gt;_getBlocks( $namespace, $rootDirectory, [ \t\t\t'Block' =&gt; [ \t\t\t\t'Block_C.php' =&gt; $this-&gt;_getControllerClassFile( \"{$namespace}\\Block\", 'Block_C' ), \t\t\t], \t\t] );  \t\t$this-&gt;assertEquals( [ \t\t\t\"{$namespace}\\Block\\Block_C\", \t\t], $blocks-&gt;getLoadedControllerClasses() );  \t}  \tpublic function testLoadAllIgnoreControllersWithoutPrefix() {  \t\t$rootDirectory = $this-&gt;_getUniqueDirectory( __METHOD__ ); \t\t$namespace     = $this-&gt;_getUniqueControllerNamespaceWithAutoloader( __METHOD__, $rootDirectory ); \t\t$blocks        = $this-&gt;_getBlocks( $namespace, $rootDirectory, [ \t\t\t'Block' =&gt; [ \t\t\t\t'Block.php' =&gt; $this-&gt;_getControllerClassFile( \"{$namespace}\\Block\", 'Block' ), \t\t\t], \t\t] );  \t\t$this-&gt;assertEquals( [], $blocks-&gt;getLoadedControllerClasses() );  \t}  \tpublic function testLoadAllIgnoreWrongControllers() {  \t\t$rootDirectory = $this-&gt;_getUniqueDirectory( __METHOD__ ); \t\t$namespace     = $this-&gt;_getUniqueControllerNamespaceWithAutoloader( __METHOD__, $rootDirectory ); \t\t$blocks        = $this-&gt;_getBlocks( $namespace, $rootDirectory, [ \t\t\t'Block' =&gt; [ \t\t\t\t'Block_C.php' =&gt; $this-&gt;_getControllerClassFile( \"{$namespace}\\Block\", 'WrongBlock_C' ), \t\t\t], \t\t] );  \t\t$this-&gt;assertEquals( [], $blocks-&gt;getLoadedControllerClasses() );  \t}  \t\/\/\/\/  \tpublic function testRenderBlockAddsControllerToUsedList() {  \t\t$rootDirectory = $this-&gt;_getUniqueDirectory( __METHOD__ ); \t\t$namespace     = $this-&gt;_getUniqueControllerNamespaceWithAutoloader( __METHOD__, $rootDirectory ); \t\t$blocks        = $this-&gt;_getBlocks( $namespace, $rootDirectory, [] ); \t\t$controller    = $this-&gt;_getController();  \t\t$blocks-&gt;renderBlock( $controller );  \t\t$this-&gt;assertEquals( [ \t\t\tget_class( $controller ), \t\t], $blocks-&gt;getUsedControllerClasses() );  \t}  \tpublic function testRenderBlockAddsControllerDependenciesToUsedList() {  \t\t$rootDirectory = $this-&gt;_getUniqueDirectory( __METHOD__ ); \t\t$namespace     = $this-&gt;_getUniqueControllerNamespaceWithAutoloader( __METHOD__, $rootDirectory ); \t\t$blocks        = $this-&gt;_getBlocks( $namespace, $rootDirectory, [] ); \t\t$controller    = $this-&gt;_getController( [ 'A', ] );  \t\t$blocks-&gt;renderBlock( $controller );  \t\t$this-&gt;assertEquals( [ \t\t\t'A', \t\t\tget_class( $controller ), \t\t], $blocks-&gt;getUsedControllerClasses() );  \t}  \tpublic function testRenderBlockAddsDependenciesBeforeControllerToUsedList() {  \t\t$rootDirectory = $this-&gt;_getUniqueDirectory( __METHOD__ ); \t\t$namespace     = $this-&gt;_getUniqueControllerNamespaceWithAutoloader( __METHOD__, $rootDirectory ); \t\t$blocks        = $this-&gt;_getBlocks( $namespace, $rootDirectory, [] ); \t\t$controller    = $this-&gt;_getController( [ 'A', ] );  \t\t$blocks-&gt;renderBlock( $controller );  \t\t$this-&gt;assertEquals( [ \t\t\t'A', \t\t\tget_class( $controller ), \t\t], $blocks-&gt;getUsedControllerClasses() );  \t}  \tpublic function testRenderBlockIgnoreDuplicateControllerWhenAddsToUsedList() {  \t\t$rootDirectory = $this-&gt;_getUniqueDirectory( __METHOD__ ); \t\t$namespace     = $this-&gt;_getUniqueControllerNamespaceWithAutoloader( __METHOD__, $rootDirectory ); \t\t$blocks        = $this-&gt;_getBlocks( $namespace, $rootDirectory, [] ); \t\t$controllerA   = $this-&gt;_getController();  \t\t$blocks-&gt;renderBlock( $controllerA ); \t\t$blocks-&gt;renderBlock( $controllerA );  \t\t$this-&gt;assertEquals( [ \t\t\tget_class( $controllerA ), \t\t], $blocks-&gt;getUsedControllerClasses() );  \t}  \tpublic function testRenderBlockIgnoreDuplicateControllerDependenciesWhenAddsToUsedList() {  \t\t$rootDirectory = $this-&gt;_getUniqueDirectory( __METHOD__ ); \t\t$namespace     = $this-&gt;_getUniqueControllerNamespaceWithAutoloader( __METHOD__, $rootDirectory ); \t\t$blocks        = $this-&gt;_getBlocks( $namespace, $rootDirectory, [] ); \t\t$controllerA   = $this-&gt;_getController( [ 'A', ] ); \t\t$controllerB   = $this-&gt;_getController( [ 'A', ] );  \t\t$blocks-&gt;renderBlock( $controllerA ); \t\t$blocks-&gt;renderBlock( $controllerB );  \t\t$this-&gt;assertEquals( [ \t\t\t'A', \t\t\tget_class( $controllerA ),\/\/ $controllerB has the same class \t\t], $blocks-&gt;getUsedControllerClasses() );  \t}  \t\/\/\/\/  \tpublic function testGetUsedResourcesWhenBlockWithResources() {  \t\t$rootDirectory = $this-&gt;_getUniqueDirectory( __METHOD__ ); \t\t$namespace     = $this-&gt;_getUniqueControllerNamespaceWithAutoloader( __METHOD__, $rootDirectory ); \t\t$blocks        = $this-&gt;_getBlocks( $namespace, $rootDirectory, [ \t\t\t'Block' =&gt; [ \t\t\t\t'Block_C.php' =&gt; $this-&gt;_getControllerClassFile( \"{$namespace}\\Block\", 'Block_C' ), \t\t\t\t'block.css'   =&gt; 'just css code', \t\t\t], \t\t], [ \t\t\t\"{$namespace}\\Block\\Block_C\", \t\t] );  \t\t$this-&gt;assertEquals( 'just css code', \t\t\t$blocks-&gt;getUsedResources( '.css', false ) );  \t}  \tpublic function testGetUsedResourcesWhenBlockWithoutResources() {  \t\t$rootDirectory = $this-&gt;_getUniqueDirectory( __METHOD__ ); \t\t$namespace     = $this-&gt;_getUniqueControllerNamespaceWithAutoloader( __METHOD__, $rootDirectory ); \t\t$blocks        = $this-&gt;_getBlocks( $namespace, $rootDirectory, [ \t\t\t'Block' =&gt; [ \t\t\t\t'Block_C.php' =&gt; $this-&gt;_getControllerClassFile( \"{$namespace}\\Block\", 'Block_C' ), \t\t\t], \t\t], [ \t\t\t\"{$namespace}\\Block\\Block_C\", \t\t] );  \t\t$this-&gt;assertEquals( '', \t\t\t$blocks-&gt;getUsedResources( '.css', false ) );  \t}  \tpublic function testGetUsedResourcesWhenSeveralBlocks() {  \t\t$rootDirectory = $this-&gt;_getUniqueDirectory( __METHOD__ ); \t\t$namespace     = $this-&gt;_getUniqueControllerNamespaceWithAutoloader( __METHOD__, $rootDirectory ); \t\t$blocks        = $this-&gt;_getBlocks( $namespace, $rootDirectory, [ \t\t\t'BlockA' =&gt; [ \t\t\t\t'BlockA_C.php' =&gt; $this-&gt;_getControllerClassFile( \"{$namespace}\\BlockA\", 'BlockA_C' ), \t\t\t\t'block-a.css'  =&gt; 'css code for a', \t\t\t], \t\t\t'BlockB' =&gt; [ \t\t\t\t'BlockB_C.php' =&gt; $this-&gt;_getControllerClassFile( \"{$namespace}\\BlockB\", 'BlockB_C' ), \t\t\t\t'block-b.css'  =&gt; 'css code for b', \t\t\t], \t\t], [ \t\t\t\"{$namespace}\\BlockA\\BlockA_C\", \t\t\t\"{$namespace}\\BlockB\\BlockB_C\", \t\t] );  \t\t$this-&gt;assertEquals( 'css code for acss code for b', \t\t\t$blocks-&gt;getUsedResources( '.css', false ) );  \t}  \tpublic function testGetUsedResourcesWithIncludedSource() {  \t\t$rootDirectory = $this-&gt;_getUniqueDirectory( __METHOD__ ); \t\t$namespace     = $this-&gt;_getUniqueControllerNamespaceWithAutoloader( __METHOD__, $rootDirectory ); \t\t$blocks        = $this-&gt;_getBlocks( $namespace, $rootDirectory, [ \t\t\t'SimpleBlock' =&gt; [ \t\t\t\t'SimpleBlock_C.php' =&gt; $this-&gt;_getControllerClassFile( \"{$namespace}\\SimpleBlock\", 'SimpleBlock_C' ), \t\t\t\t'simple-block.css'  =&gt; 'css code', \t\t\t], \t\t], [ \t\t\t\"{$namespace}\\SimpleBlock\\SimpleBlock_C\", \t\t] );  \t\t$this-&gt;assertEquals( \"\\n\/* simple-block *\/\\ncss code\", \t\t\t$blocks-&gt;getUsedResources( '.css', true ) );  \t}  } <\/code><\/pre>\n<\/div>\n<\/details>\n<p>\u0412\u043e\u0442 \u0438 \u0432\u0441\u0435, \u0442\u0435\u043f\u0435\u0440\u044c \u043e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0438\u0442\u044c \u044d\u0442\u0438 \u0447\u0430\u0441\u0442\u0438 \u0438 \u043d\u0430\u0448 \u043c\u0438\u043d\u0438-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0433\u043e\u0442\u043e\u0432. \u041c\u043e\u043c\u0435\u043d\u0442 \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438 composer \u043f\u0430\u043a\u0435\u0442\u0430 \u044f \u043e\u043f\u0443\u0449\u0443, \u0442.\u043a. \u044d\u0442\u043e \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430 \u0438 \u0435\u0441\u043b\u0438 \u0432\u0430\u043c \u0431\u0443\u0434\u0435\u0442 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e \u0442\u043e \u0432\u044b \u0431\u0435\u0437 \u0442\u0440\u0443\u0434\u0430 \u043d\u0430\u0439\u0434\u0435\u0442\u0435 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043f\u043e \u044d\u0442\u043e\u043c\u0443 \u043f\u043e\u0432\u043e\u0434\u0443.<\/p>\n<h2> \u0414\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u043f\u0440\u0438\u043c\u0435\u0440<\/h2>\n<p>\u041d\u0438\u0436\u0435 \u043f\u0440\u0438\u0432\u0435\u0434\u0443 \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u0430\u043a\u0435\u0442\u0430, \u0441 \u043e\u0434\u043d\u0438\u043c \u0447\u0438\u0441\u0442\u044b\u043c css \u0434\u043b\u044f \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e\u0441\u0442\u0438, \u0435\u0441\u043b\u0438 \u043a\u043e\u043c\u0443-\u0442\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0435\u043d \u043f\u0440\u0438\u043c\u0435\u0440 \u0441 scss\/webpack \u0441\u043c\u043e\u0442\u0440\u0438\u0442\u0435 \u0441\u0441\u044b\u043b\u043a\u0438 \u0432 \u043a\u043e\u043d\u0446\u0435 \u0441\u0442\u0430\u0442\u044c\u0438.<\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0431\u043b\u043e\u043a\u0438 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0430, BlockA \u0438 BlockC \u0431\u0443\u0434\u0443\u0442 \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u044b\u043c\u0438 \u0431\u043b\u043e\u043a\u0430\u043c\u0438, BlockB \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u043a\u0430\u0442\u044c BlockC.<\/p>\n<p><strong>BlockA<\/strong><\/p>\n<details class=\"spoiler\">\n<summary>BlockA.php<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php  namespace LightSource\\FrontBlocksExample\\BlockA;  use LightSource\\FrontBlocksFramework\\MODEL;  class BlockA extends MODEL {  \tprotected string $_name;  \tpublic function load() {  \t\tparent::_load(); \t\t$this-&gt;_name = 'I\\'m BlockA';  \t}  } <\/code><\/pre>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>BlockA_C.php<\/summary>\n<div class=\"spoiler__content\">\n<p>\/sp<\/p>\n<pre><code class=\"php\">&lt;?php  namespace LightSource\\FrontBlocksExample\\BlockA;  use LightSource\\FrontBlocksFramework\\Blocks; use LightSource\\FrontBlocksFramework\\CONTROLLER;  class BlockA_C extends CONTROLLER {  \tpublic function getModel(): ?BlockA { \t\t\/** @noinspection PhpIncompatibleReturnTypeInspection *\/ \t\treturn parent::getModel(); \t}  } <\/code><\/pre>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>block-a.twig<\/summary>\n<div class=\"spoiler__content\">\n<p>\/<\/p>\n<pre><code>&lt;div class=\"block-a\"&gt;     {{ name }} &lt;\/div&gt;<\/code><\/pre>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>block-a.css<\/summary>\n<div class=\"spoiler__content\">\n<p>Bl<\/p>\n<pre><code class=\"css\">.block-a {     color: green;     border:1px solid green;     padding: 10px; } <\/code><\/pre>\n<\/div>\n<\/details>\n<p><strong>BlockB<\/strong><\/p>\n<details class=\"spoiler\">\n<summary>BlockB.php<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php  namespace LightSource\\FrontBlocksExample\\BlockB;  use LightSource\\FrontBlocksExample\\BlockC\\BlockC; use LightSource\\FrontBlocksFramework\\MODEL;  class BlockB extends MODEL {  \tprotected string $_name; \tprotected BlockC $_blockC;  \tpublic function __construct() {  \t\tparent::__construct();  \t\t$this-&gt;_blockC = new BlockC();  \t}  \tpublic function load() {  \t\tparent::_load(); \t\t$this-&gt;_name = 'I\\'m BlockB, I contain another block'; \t\t$this-&gt;_blockC-&gt;load();  \t}  } <\/code><\/pre>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>BlockB_C.php<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php  namespace LightSource\\FrontBlocksExample\\BlockB;  use LightSource\\FrontBlocksExample\\BlockC\\BlockC_C; use LightSource\\FrontBlocksFramework\\CONTROLLER;  class BlockB_C extends CONTROLLER {  \tprotected BlockC_C $_blockC;  \tpublic function getModel(): ?BlockB { \t\t\/** @noinspection PhpIncompatibleReturnTypeInspection *\/ \t\treturn parent::getModel(); \t}  } <\/code><\/pre>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>block-b.twig<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>&lt;div class=\"block-b\"&gt;      &lt;p class=\"block-b__name\"&gt;{{ name }}&lt;\/p&gt;      {{ _include(blockC) }}  &lt;\/div&gt;<\/code><\/pre>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>block-b.css<\/summary>\n<div class=\"spoiler__content\">\n<p>Blo<\/p>\n<pre><code class=\"css\">.block-b {     color: orange;     border: 1px solid orange;     padding: 10px; }  .block-b__name {     margin: 0 0 10px;     line-height: 1.5; } <\/code><\/pre>\n<\/div>\n<\/details>\n<p><strong>BlocksC<\/strong><\/p>\n<details class=\"spoiler\">\n<summary>BlockC.php<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php  namespace LightSource\\FrontBlocksExample\\BlockC;  use LightSource\\FrontBlocksFramework\\MODEL;  class BlockC extends MODEL {  \tprotected string $_name;  \tpublic function load() {  \t\tparent::_load(); \t\t$this-&gt;_name = 'I\\'m BlockC';  \t}  } <\/code><\/pre>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>BlockC_C.php<\/summary>\n<div class=\"spoiler__content\">\n<p>\/<\/p>\n<pre><code class=\"php\">&lt;?php  namespace LightSource\\FrontBlocksExample\\BlockC;  use LightSource\\FrontBlocksFramework\\CONTROLLER;  class BlockC_C extends CONTROLLER {  \tpublic function getModel(): ?BlockC { \t\t\/** @noinspection PhpIncompatibleReturnTypeInspection *\/ \t\treturn parent::getModel(); \t}  } <\/code><\/pre>\n<p> \u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u043c \u043d\u0430\u0448 \u043f\u0430\u043a\u0435\u0442 \u0438 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043c \u0431\u043b\u043e\u043a\u0438<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>block-c.twig<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>&lt;div class=\"block-c\"&gt;     {{ name }} &lt;\/div&gt;<\/code><\/pre>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>block-c.css<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"css\">.block-c {     color: black;     border: 1px solid black;     padding: 10px; } <\/code><\/pre>\n<\/div>\n<\/details>\n<p>\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u043c \u043d\u0430\u0448 \u043f\u0430\u043a\u0435\u0442 \u0438 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043c \u0431\u043b\u043e\u043a\u0438, \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0432\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0432 html \u043a\u043e\u0434 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b, \u0432 \u0448\u0430\u043f\u043a\u0435 \u0432\u044b\u0432\u043e\u0434\u0438\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0439 css \u043a\u043e\u0434<\/p>\n<details class=\"spoiler\">\n<summary>example.php<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php  use LightSource\\FrontBlocksExample\\{ \tBlockA\\BlockA_C, \tBlockB\\BlockB_C, }; use LightSource\\FrontBlocksFramework\\{ \tBlocks, \tSettings };  require_once __DIR__ . '\/vendors\/vendor\/autoload.php';  \/\/\/\/ settings  $settings = new Settings(); $settings-&gt;setBlocksDirNamespace( 'LightSource\\FrontBlocksExample' ); $settings-&gt;setBlocksDirPath( __DIR__ . '\/Blocks' ); $settings-&gt;setErrorCallback( function ( array $errors ) { \t\/\/ todo log or any other actions \techo '&lt;pre&gt;' . print_r( $errors, true ) . '&lt;\/pre&gt;'; } ); $blocks = new Blocks( $settings );  \/\/\/\/ usage  $blockA_Controller = new BlockA_C(); $blockA_Controller-&gt;getModel()-&gt;load();  $blockB_Controller = new BlockB_C(); $blockB_Controller-&gt;getModel()-&gt;load();  $content = $blocks-&gt;renderBlock( $blockA_Controller ); $content .= $blocks-&gt;renderBlock( $blockB_Controller ); $css     = $blocks-&gt;getUsedResources( '.css', true );  \/\/\/\/ html  ?&gt; &lt;html&gt;  &lt;head&gt;      &lt;title&gt;Example&lt;\/title&gt;     &lt;style&gt;         &lt;?= $css ?&gt;     &lt;\/style&gt;     &lt;style&gt;         .block-b {             margin-top: 10px;         }     &lt;\/style&gt;  &lt;\/head&gt;  &lt;body&gt;  &lt;?= $content ?&gt;  &lt;\/body&gt;  &lt;\/html&gt; <\/code><\/pre>\n<\/div>\n<\/details>\n<p>\u0432 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u0432\u044b\u0432\u043e\u0434 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a\u0438\u043c<\/p>\n<details class=\"spoiler\">\n<summary>example.png<\/summary>\n<div class=\"spoiler__content\">\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/ea1\/5f6\/041\/ea15f6041ffd2de591ce47770efb3887.png\" width=\"1511\" height=\"164\"><figcaption><\/figcaption><\/figure>\n<\/div>\n<\/details>\n<h2>\u041f\u043e\u0441\u043b\u0435\u0441\u043b\u043e\u0432\u0438\u0435<\/h2>\n<p>\u0414\u0430\u043d\u043d\u044b\u0439 \u043f\u0430\u043a\u0435\u0442 \u0431\u044b\u043b \u0441\u043e\u0437\u0434\u0430\u043d \u0434\u043b\u044f \u043b\u0438\u0447\u043d\u044b\u0445 \u0446\u0435\u043b\u0435\u0439, \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e \u0435\u0433\u043e \u0432 \u0441\u0432\u043e\u0438\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445 \u0438 \u043e\u043d \u043e\u0431\u043b\u0435\u0433\u0447\u0430\u0435\u0442 \u043c\u043d\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443, \u0438 \u044f \u0431\u0443\u0434\u0443 \u0440\u0430\u0434 \u0435\u0441\u043b\u0438 \u043e\u043d \u043f\u0440\u0438\u0433\u043e\u0434\u0438\u0442\u0441\u044f \u043a\u043e\u043c\u0443-\u0442\u043e \u0435\u0449\u0435. \u041d\u0435 \u0441\u0442\u0435\u0441\u043d\u044f\u0439\u0442\u0435\u0441\u044c \u0437\u0430\u0434\u0430\u0432\u0430\u0442\u044c \u0432\u043e\u043f\u0440\u043e\u0441\u044b \u0438 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u2013 \u044f \u0431\u0443\u0434\u0443 \u0440\u0430\u0434 \u043e\u0442\u0432\u0435\u0442\u0438\u0442\u044c \u043d\u0430 \u0432\u0430\u0448\u0438 \u0432\u043e\u043f\u0440\u043e\u0441\u044b \u0438 \u0443\u0441\u043b\u044b\u0448\u0430\u0442\u044c \u0432\u0430\u0448\u0435 \u043c\u043d\u0435\u043d\u0438\u0435.<\/p>\n<p>\u0412\u043e\u0442 \u0438 \u0432\u0441\u0435, \u0441\u043f\u0430\u0441\u0438\u0431\u043e \u0437\u0430 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435.<\/p>\n<p>\u0421\u0441\u044b\u043b\u043a\u0438:<\/p>\n<p><a href=\"https:\/\/github.com\/light-source\/front-blocks-framework\" rel=\"noopener noreferrer nofollow\">\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0441 \u043c\u0438\u043d\u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u043c<\/a><\/p>\n<p><a href=\"https:\/\/github.com\/light-source\/front-blocks-example\/\" rel=\"noopener noreferrer nofollow\">\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0441 \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u043c<\/a><\/p>\n<p><a href=\"https:\/\/github.com\/light-source\/front-blocks-webpack-example\" rel=\"noopener noreferrer nofollow\">\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0441 \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f scss \u0438 js \u0432 \u0431\u043b\u043e\u043a\u0430\u0445<\/a> <a href=\"https:\/\/github.com\/light-source\/front-blocks-webpack-example\" rel=\"noopener noreferrer nofollow\">(webpack \u0441\u0431\u043e\u0440\u0449\u0438\u043a)<\/a><\/p>\n<p><a href=\"https:\/\/github.com\/light-source\/wp-theme-bones\" rel=\"noopener noreferrer nofollow\">\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0441 \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0432 WordPress \u0442\u0435\u043c\u0435<\/a> (\u0437\u0434\u0435\u0441\u044c \u0432\u044b \u0442\u0430\u043a\u0436\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u0443\u0432\u0438\u0434\u0435\u0442\u044c <a href=\"https:\/\/github.com\/light-source\/wp-theme-bones\/blob\/master\/Classes\/CONTROLLER.php\" rel=\"noopener noreferrer nofollow\">\u043f\u0440\u0438\u043c\u0435\u0440 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f \u043a\u043b\u0430\u0441\u0441\u0430 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430<\/a> \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0430\u0432\u0442\u043e\u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0432\u0441\u0435\u0445 \u043a\u043e\u043d\u0442\u043e\u043b\u043b\u0435\u0440\u043e\u0432, \u0447\u0442\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 ajax \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0434\u043b\u044f \u0431\u043b\u043e\u043a\u043e\u0432).<\/p>\n<\/div>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/post\/556494\/\"> https:\/\/habr.com\/ru\/post\/556494\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"\n<div class=\"post__text post__text_v2\" id=\"post-content-body\">\n<p>\u0414\u043e\u0431\u0440\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0441\u0443\u0442\u043e\u043a \u0443\u0432\u0430\u0436\u0430\u0435\u043c\u044b\u0435 \u0447\u0438\u0442\u0430\u0442\u0435\u043b\u0438 \u0445\u0430\u0431\u0440\u0430. \u0421 \u043a\u0430\u0436\u0434\u044b\u043c \u0433\u043e\u0434\u043e\u043c \u0432 \u0432\u0435\u0431 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u043f\u043e\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432\u0441\u0435 \u0431\u043e\u043b\u044c\u0448\u0435 \u0440\u0430\u0437\u043d\u043e\u043e\u0431\u0440\u0430\u0437\u043d\u044b\u0445 \u0440\u0435\u0448\u0435\u043d\u0438\u0439 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 \u043c\u043e\u0434\u0443\u043b\u044c\u043d\u044b\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u0438 \u0443\u043f\u0440\u043e\u0449\u0430\u044e\u0442 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0438 \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043a\u043e\u0434\u0430. \u0412 \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u0432\u0430\u043c \u0441\u0432\u043e\u0439 \u0432\u0437\u0433\u043b\u044f\u0434 \u043d\u0430 \u0442\u043e, \u043a\u0430\u043a\u0438\u043c\u0438 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0435 front-end \u0431\u043b\u043e\u043a\u0438 (\u0434\u043b\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432 \u0441 \u0431\u044d\u043a\u0435\u043d\u0434\u043e\u043c \u043d\u0430 php) \u0438 \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u043f\u0440\u043e\u0439\u0442\u0438 \u0432\u0441\u0435 \u0448\u0430\u0433\u0438 \u043e\u0442 \u0438\u0434\u0435\u0438 \u0434\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0432\u043c\u0435\u0441\u0442\u0435 \u0441\u043e \u043c\u043d\u043e\u0439. \u0417\u0432\u0443\u0447\u0438\u0442 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e? \u0422\u043e\u0433\u0434\u0430 \u0434\u043e\u0431\u0440\u043e \u043f\u043e\u0436\u0430\u043b\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0434 \u043a\u0430\u0442.<\/p>\n<h2>\u041f\u0440\u0435\u0434\u0438\u0441\u043b\u043e\u0432\u0438\u0435<\/h2>\n<p>\u041f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044e\u0441\u044c &#8212; \u044f \u043c\u043e\u043b\u043e\u0434\u043e\u0439 \u0432\u0435\u0431 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0441 \u043e\u043f\u044b\u0442\u043e\u043c \u0440\u0430\u0431\u043e\u0442\u044b 5 \u043b\u0435\u0442.  \u041a\u0440\u0430\u0439\u043d\u0438\u0439 \u0433\u043e\u0434 \u044f \u0440\u0430\u0431\u043e\u0442\u0430\u044e \u043d\u0430 \u0444\u0440\u0438\u043b\u0430\u043d\u0441\u0435 \u0438 \u0431\u043e\u043b\u044c\u0448\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u0442\u0435\u043a\u0443\u0449\u0438\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432 \u0441\u0432\u044f\u0437\u0430\u043d\u0430 \u0441 WordPress. \u041d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u0440\u0430\u0437\u043b\u0438\u0447\u0443\u044e \u043a\u0440\u0438\u0442\u0438\u043a\u0443 CMS \u0432 \u043e\u0431\u0449\u0435\u043c \u0438 WordPress \u0432 \u0447\u0430\u0441\u043d\u043e\u0441\u0442\u0438, \u044f \u0441\u0447\u0438\u0442\u0430\u044e \u0441\u0430\u043c\u0430 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 WordPress \u044d\u0442\u043e \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0443\u0434\u0430\u0447\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435, \u0445\u043e\u0442\u044f \u043a\u043e\u043d\u0435\u0447\u043d\u043e \u043d\u0435 \u0431\u0435\u0437 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0445 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043a\u043e\u0432. \u0418 \u043e\u0434\u0438\u043d \u0438\u0437 \u043d\u0438\u0445 \u043d\u0430 \u043c\u043e\u0439 \u0432\u0437\u0433\u043b\u044f\u0434 \u044d\u0442\u043e \u0448\u0430\u0431\u043b\u043e\u043d\u044b. \u0412 \u043a\u0440\u0430\u0439\u043d\u0438\u0445 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f\u0445 \u0441\u0434\u0435\u043b\u0430\u043d\u044b \u0431\u043e\u043b\u044c\u0448\u0438\u0435 \u0448\u0430\u0433\u0438 \u0447\u0442\u043e\u0431\u044b \u044d\u0442\u043e \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u0442\u044c, \u0438 Gutenberg \u0432 \u0446\u0435\u043b\u043e\u043c \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u043c\u043e\u0449\u043d\u044b\u043c \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u043c, \u043e\u0434\u043d\u0430\u043a\u043e \u043a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e \u0432 \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u0435 \u0442\u0435\u043c \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0435\u0442\u0441\u044f \u043a\u0430\u0448\u0430 \u0432 \u0448\u0430\u0431\u043b\u043e\u043d\u0430\u0445, \u0441\u0442\u0438\u043b\u044f\u0445 \u0438 \u0441\u043a\u0440\u0438\u043f\u0442\u0430\u0445, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0434\u0435\u043b\u0430\u0435\u0442 \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0447\u0435\u0433\u043e-\u043b\u0438\u0431\u043e \u043a\u0440\u0430\u0439\u043d\u0435 \u0431\u043e\u043b\u0435\u0437\u043d\u0435\u043d\u043d\u044b\u043c, \u0430 \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043a\u043e\u0434\u0430 \u0437\u0430\u0447\u0430\u0441\u0442\u0443\u044e \u043d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u043c. \u0418\u043c\u0435\u043d\u043d\u043e \u044d\u0442\u0430 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0438 \u043f\u043e\u0434\u0442\u043e\u043b\u043a\u043d\u0443\u043b\u043e \u043c\u0435\u043d\u044f \u043a \u0438\u0434\u0435\u0435 \u0441\u0432\u043e\u0435\u0433\u043e \u043c\u0438\u043d\u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 (\u0447\u0438\u0442\u0430\u0439 \u043f\u0430\u043a\u0435\u0442\u0430, \u043d\u043e \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043e\u043d \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0435\u0434\u044a\u044f\u0432\u043b\u044f\u0442\u044c \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u043a \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435, \u0442\u043e \u0433\u043e\u0440\u0434\u043e \u043d\u0430\u0437\u043e\u0432\u0435\u043c \u043c\u0438\u043d\u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u043c),  \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u044b \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u043b \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u0438 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u043b \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0431\u043b\u043e\u043a\u0438.  <\/p>\n<p>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0431\u0443\u0434\u0435\u0442 \u0432 \u0432\u0438\u0434\u0435 composer \u043f\u0430\u043a\u0435\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043e\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432 \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u043e \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445, \u0431\u0435\u0437 \u043f\u0440\u0438\u0432\u044f\u0437\u043a\u0438 \u043a WordPress.  <\/p>\n<p>\u041c\u043e\u0442\u0438\u0432\u043e\u043c \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u0443\u044e \u0441\u0442\u0430\u0442\u044c\u044e \u0431\u044b\u043b\u043e \u0436\u0435\u043b\u0430\u043d\u0438\u0435 \u043f\u043e\u0434\u0435\u043b\u0438\u0442\u0441\u044f \u0440\u0435\u0448\u0435\u043d\u0438\u0435\u043c \u0434\u043b\u044f \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u043c\u043e\u0434\u0443\u043b\u044c\u043d\u044b\u0445 \u0431\u043b\u043e\u043a\u043e\u0432,  \u0430 \u0442\u0430\u043a\u0436\u0435 \u0436\u0435\u043b\u0430\u043d\u0438\u0435 \u0447\u0438\u0442\u0430\u0442\u0435\u043b\u044f \u0445\u0430\u0431\u0440\u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u044e \u0441\u0442\u0430\u0442\u044c\u044e, \u0447\u0442\u043e \u0441\u0440\u043e\u0434\u043d\u0438 \u0436\u0435\u043b\u0430\u043d\u0438\u044e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0441\u0432\u043e\u0439 \u043f\u0430\u043a\u0435\u0442, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043f\u043e\u0440\u043e\u0439 \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u0435\u0442 \u0443 \u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0449\u0438\u0445 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0433\u043e\u0442\u043e\u0432\u044b\u0435 \u043f\u0430\u043a\u0435\u0442\u044b composer \u0438\u043b\u0438 npm.<\/p>\n<p>\u041a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0438\u0437 \u0442\u0435\u043a\u0441\u0442\u0430 \u0432\u044b\u0448\u0435, \u044d\u0442\u043e \u043c\u043e\u044f \u043f\u0435\u0440\u0432\u0430\u044f \u0441\u0442\u0430\u0442\u044c\u044f \u043d\u0430 \u0445\u0430\u0431\u0440\u0435, \u043f\u043e-\u044d\u0442\u043e\u043c\u0443 \u043f\u0440\u043e\u0441\u044c\u0431\u0430 <s>\u043d\u0435 \u0431\u0440\u043e\u0441\u0430\u0442\u044c \u043f\u043e\u043c\u0438\u0434\u043e\u0440\u044b<\/s> \u043d\u0435 \u0441\u0443\u0434\u0438\u0442\u044c \u0441\u0442\u0440\u043e\u0433\u043e.  <\/p>\n<h2>\u041f\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0437\u0430\u0434\u0430\u0447\u0438<\/h2>\n<p>\u041f\u043e\u043d\u044f\u0442\u0438\u0435 \u0431\u043b\u043e\u043a \u043d\u0438\u0436\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e \u0441\u0443\u0442\u0438 \u0442\u0435\u043c \u0436\u0435 \u043f\u043e\u043d\u044f\u0442\u0438\u0435\u043c \u0447\u0442\u043e \u0438 \u0431\u043b\u043e\u043a \u0432 <a href=\"https:\/\/ru.bem.info\/methodology\/\" rel=\"noopener noreferrer nofollow\">BEM \u043c\u0435\u0442\u043e\u0434\u043e\u043b\u043e\u0433\u0438\u0438<\/a>,  \u0442.\u0435. \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0433\u0440\u0443\u043f\u043f\u0430 html\/js\/css \u043a\u043e\u0434\u0430 \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u043e\u0434\u043d\u0443 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044c.<\/p>\n<p>\u0413\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c html \u0438 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044f\u043c\u0438 \u0431\u043b\u043e\u043a\u043e\u0432 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0447\u0435\u0440\u0435\u0437 php, \u0447\u0442\u043e \u0433\u043e\u0432\u043e\u0440\u0438\u0442 \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u043d\u0430\u0448 \u043f\u0430\u043a\u0435\u0442 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442\u044c \u0434\u043b\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432 \u0441 \u0431\u0435\u043a\u0435\u043d\u0434\u043e\u043c \u043d\u0430 php. \u0422\u0430\u043a\u0436\u0435 \u0443\u0441\u043b\u043e\u0432\u0438\u043c\u0441\u044f \u043d\u0430 \u0431\u0435\u0440\u0435\u0433\u0443 \u0447\u0442\u043e, \u043d\u0435 \u0432\u0434\u0430\u0432\u0430\u044f\u0441\u044c \u0432 \u0441\u043f\u043e\u0440\u044b, \u043d\u0435 \u0431\u0443\u0434\u0435\u043c \u043f\u043e\u0434\u0434\u0430\u0432\u0430\u0442\u044c\u0441\u044f \u0432\u043b\u0438\u044f\u043d\u0438\u044e \u043d\u043e\u0432\u043e\u043c\u043e\u0434\u043d\u044b\u0445 \u0432\u0435\u0449\u0435\u0439, \u0442\u0430\u043a\u0438\u0445 \u043a\u0430\u043a css-in-js \u0438\u043b\u0438 bem-json \u0438 \u0431\u0443\u0434\u0435\u043c \u043f\u0440\u0438\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c\u0441\u044f <s>\u044d\u043b\u044c-\u043a\u043b\u0430\u0441\u0441\u0438\u043a\u043e<\/s> \u043a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0430, \u0442.\u0435. \u043f\u0440\u0435\u0434\u043f\u043e\u043b\u0430\u0433\u0430\u0442\u044c \u0447\u0442\u043e html, css \u0438 js \u044d\u0442\u043e \u0440\u0430\u0437\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u044b.  <\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0441\u0444\u043e\u0440\u043c\u0443\u043b\u0438\u0440\u0443\u0435\u043c \u043d\u0430\u0448\u0438 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u043a \u0431\u0443\u0434\u0443\u0449\u0435\u043c\u0443 \u043c\u0438\u043d\u0438-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0443:<\/p>\n<ul>\n<li>\n<p>\u041e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442\u044c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u0431\u043b\u043e\u043a\u043e\u0432<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 \u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u044f (\u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f) \u0431\u043b\u043e\u043a\u043e\u0432<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\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 \u0431\u043b\u043e\u043a \u0432 \u0431\u043b\u043e\u043a\u0435  \u0438 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u043e\u0434\u043d\u043e\u0433\u043e \u0431\u043b\u043e\u043a\u0430 \u043e\u0442 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u0434\u0440\u0443\u0433\u0438\u0445 \u0431\u043b\u043e\u043a\u043e\u0432 <\/p>\n<\/li>\n<\/ul>\n<h2>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043c\u0438\u043d\u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430<\/h2>\n<p>\u041a\u0430\u043a \u0443\u0441\u043b\u043e\u0432\u0438\u043b\u0438\u0441\u044c \u0432\u044b\u0448\u0435, \u0442\u0430\u043a\u0438\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u044b \u043a\u0430\u043a css \u0438 js \u0432\u0441\u0435\u0433\u0434\u0430 \u0431\u0443\u0434\u0443\u0442 \u0432 \u0432\u0438\u0434\u0435 \u043e\u0431\u044b\u0447\u043d\u044b\u0445 \u0444\u0430\u0439\u043b\u043e\u0432, \u0442.\u0435. \u044d\u0442\u043e \u0431\u0443\u0434\u0443\u0442 .js \u0438 .css \u0438\u043b\u0438 .min.css \u0438 .min.js \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u0440\u0435\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0441\u043e\u0440\u043e\u0432 \u0438 \u0441\u0431\u043e\u0440\u0449\u0438\u043a\u043e\u0432 (\u043a\u0430\u043a webpack \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440). \u0414\u043b\u044f \u0432\u0441\u0442\u0430\u0432\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 html \u043a\u043e\u0434 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0448\u0430\u0431\u043b\u043e\u043d\u0438\u0437\u0430\u0442\u043e\u0440 Twig (\u0434\u043b\u044f \u0442\u0435\u0445 \u043a\u0442\u043e \u043d\u0435 \u0437\u043d\u0430\u043a\u043e\u043c <a href=\"https:\/\/twig.symfony.com\/\" rel=\"noopener noreferrer nofollow\">\u0441\u0441\u044b\u043b\u043a\u0430<\/a>). \u041a\u0442\u043e-\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0437\u0430\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e Php \u0438 \u0441\u0430\u043c \u043f\u043e \u0441\u0435\u0431\u0435 \u0445\u043e\u0440\u043e\u0448\u0438\u0439 \u0448\u0430\u0431\u043b\u043e\u043d\u0438\u0437\u0430\u0442\u043e\u0440, \u043d\u0435 \u0431\u0443\u0434\u0435\u043c \u0432\u0434\u0430\u0432\u0430\u0442\u044c\u0441\u044f \u0432 \u0441\u043f\u043e\u0440\u044b, \u043a\u0440\u043e\u043c\u0435 \u0434\u043e\u0432\u043e\u0434\u043e\u0432 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0445 \u043d\u0430 \u0433\u043b\u0430\u0432\u043d\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 Twig, \u043e\u0442\u043c\u0435\u0447\u0443 \u0432\u0430\u0436\u043d\u044b\u0439 \u0434\u043b\u044f \u043c\u0435\u043d\u044f \u043f\u0443\u043d\u043a\u0442, \u0442\u043e \u0447\u0442\u043e \u043e\u043d \u0434\u0438\u0441\u0446\u0438\u043f\u043b\u0438\u043d\u0438\u0440\u0443\u0435\u0442, \u0442.\u0435. \u0437\u0430\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u043e\u0442\u0434\u0435\u043b\u044f\u0442\u044c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u043e\u0442 \u0432\u044b\u0432\u043e\u0434\u0430 \u0438 \u043f\u043e\u0434\u0433\u043e\u0442\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0437\u0430\u0440\u0430\u043d\u0435\u0435, \u0438 \u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e.  <\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u0440\u043e\u0434\u0443\u043c\u0430\u0435\u043c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u043d\u0430\u0448\u0435\u0433\u043e \u043c\u0438\u043d\u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 \u0431\u043e\u043b\u0435\u0435 \u0434\u0435\u0442\u0430\u043b\u044c\u043d\u043e.  <\/p>\n<ol>\n<li>\n<p> \u0411\u043b\u043e\u043a<\/p>\n<p> \u041a\u0430\u0436\u0434\u044b\u0439 \u0431\u043b\u043e\u043a \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u0442\u044c \u0438\u0437:<\/p>\n<ol>\n<li>\n<p>\u0421\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 (css\/js\/twig)<\/p>\n<\/li>\n<li>\n<p>\u041a\u043b\u0430\u0441\u0441\u0430 \u043c\u043e\u0434\u0435\u043b\u0438 (\u0435\u0433\u043e \u043f\u043e\u043b\u044f \u043c\u044b \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u043a\u0430\u043a \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f twig \u0448\u0430\u0431\u043b\u043e\u043d\u0430)<\/p>\n<\/li>\n<li>\n<p> \u041a\u043b\u0430\u0441\u0441\u0430 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0435\u0440\u0430 (\u043e\u043d \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u0432\u0435\u0447\u0430\u0442\u044c \u0437\u0430 \u043d\u0430\u0448\u0438 \u0440\u0435\u0441\u0443\u0440\u0441\u044b, \u0438\u0445 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0434\u0440\u0443\u0433 \u043e\u0442 \u0434\u0440\u0443\u0433\u0430 \u0438 \u0441\u0432\u044f\u0437\u044b\u0432\u0430\u0442\u044c \u043c\u043e\u0434\u0435\u043b\u044c \u0441 twig \u0448\u0430\u0431\u043b\u043e\u043d\u043e\u043c)<\/p>\n<\/li>\n<\/ol>\n<\/li>\n<li>\n<p> \u0412\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043a\u043b\u0430\u0441\u0441\u044b : \u041a\u043b\u0430\u0441\u0441 Settings (\u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u043f\u0443\u0442\u044c \u043a \u0431\u043b\u043e\u043a\u0430\u043c, \u0438\u0445 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e \u0438\u043c\u0435\u043d \u0438 \u0442.\u0434.), \u043a\u043b\u0430\u0441\u0441 \u043e\u0431\u0435\u0440\u0442\u043a\u0430 \u0434\u043b\u044f Twig \u043f\u0430\u043a\u0435\u0442\u0430<\/p>\n<\/li>\n<li>\n<p> Blocks \u043a\u043b\u0430\u0441\u0441<\/p>\n<p> \u0421\u0432\u044f\u0437\u0443\u044e\u0449\u0438\u0439 \u043a\u043b\u0430\u0441\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 :<\/p>\n<ol>\n<li>\n<p> \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043a\u043b\u0430\u0441\u0441\u044b (Settings, Twig)<\/p>\n<\/li>\n<li>\n<p>\u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0440\u0435\u043d\u0434\u0435\u0440\u0430 \u0431\u043b\u043e\u043a\u0430<\/p>\n<\/li>\n<li>\n<p>\u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0431\u043b\u043e\u043a\u043e\u0432, \u0447\u0442\u043e\u0431\u044b \u0438\u043c\u0435\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0438\u0445 \u0440\u0435\u0441\u0443\u0440\u0441\u044b (css\/js)<\/p>\n<\/li>\n<li>\n<p>\u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044c \u0432\u0441\u0435 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u044b (\u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0437\u0430\u0434\u0435\u043b \u043d\u0430 \u0431\u0443\u0434\u0443\u0449\u0435\u0435, \u044d\u0442\u043e \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0432\u044b\u0445\u043e\u0434\u0438\u0442 \u0437\u0430 \u0440\u0430\u043c\u043a\u0438 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0441\u0442\u0430\u0442\u044c\u0438, \u0441\u043a\u0430\u0436\u0443 \u043f\u0440\u043e\u0441\u0442\u043e \u0447\u0442\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u043e\u0432 \u0438 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f)<\/p>\n<\/li>\n<\/ol>\n<\/li>\n<\/ol>\n<h2> \u0422\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u043a \u0431\u043b\u043e\u043a\u0430\u043c<\/h2>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043a\u043e\u0433\u0434\u0430 \u043c\u044b \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043b\u0438\u0441\u044c \u0441\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043e\u0439 \u043f\u0440\u0438\u0448\u043b\u043e \u0432\u0440\u0435\u043c\u044f <s>\u0437\u0430\u0436\u0435\u0447\u044c<\/s> \u043e\u043f\u0440\u0430\u0432\u0434\u0430\u0442\u044c \u0441\u043b\u043e\u0432\u043e \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0432 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0438 \u0434\u043b\u044f \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0430\u043a\u0435\u0442\u0430, \u0430 \u0438\u043c\u0435\u043d\u043d\u043e \u2013 \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u043a \u043a\u043e\u0434\u0443 \u043d\u0430\u0448\u0438\u0445 \u0431\u043b\u043e\u043a\u043e\u0432:<\/p>\n<ul>\n<li>\n<p> php 7.4+<\/p>\n<\/li>\n<li>\n<p> \u0412\u0441\u0435 \u0431\u043b\u043e\u043a\u0438 \u0434\u043e\u043b\u0436\u043d\u044b \u0438\u043c\u0435\u0442\u044c \u043e\u0434\u043d\u0443 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0443\u044e \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e<\/p>\n<\/li>\n<li>\n<p> \u041a\u043b\u0430\u0441\u0441\u044b \u043c\u043e\u0434\u0435\u043b\u0435\u0439 \u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u043e\u0432 \u0434\u043e\u043b\u0436\u043d\u044b \u0438\u043c\u0435\u0442\u044c PSR-4 \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u043e\u0435 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e \u0438\u043c\u0435\u043d \u0441 \u0430\u0432\u0442\u043e\u0437\u0430\u0433\u0440\u0443\u0437\u0447\u0438\u043a\u043e\u043c (<a href=\"https:\/\/www.php-fig.org\/psr\/psr-4\/\" rel=\"noopener noreferrer nofollow\">PSR-4<\/a> \u0434\u0435 \u0444\u0430\u043a\u0442\u043e \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442, \u0435\u0441\u043b\u0438 \u0432\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0435 \u0430\u0432\u0442\u043e\u0437\u0430\u0433\u0440\u0443\u0437\u0447\u0438\u043a \u043e\u0442 composer, \u0442.\u0435. \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0435 autoload\/psr4 \u0434\u0438\u0440\u0435\u043a\u0442\u0438\u0432\u0443 \u0432 \u0432\u0430\u0448\u0435\u043c composer.json \u0442\u043e \u0432\u0430\u0448 \u043f\u0440\u043e\u0435\u043a\u0442 \u0443\u0436\u0435 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u044d\u0442\u043e\u043c\u0443 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044e)  <\/p>\n<\/li>\n<li>\n<p> \u0421\u043e\u0433\u043b\u0430\u0448\u0435\u043d\u0438\u0435 \u043e\u0431 \u0438\u043c\u0435\u043d\u0430\u0445:<\/p>\n<ul>\n<li>\n<p>\u0418\u043c\u044f \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430 \u0434\u043e\u043b\u0436\u043d\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u2018_C\u2019 \u0441\u0443\u0444\u0444\u0438\u043a\u0441<\/p>\n<\/li>\n<li>\n<p> \u041a\u043b\u0430\u0441\u0441 \u043c\u043e\u0434\u0435\u043b\u0438 \u0434\u043e\u043b\u0436\u0435\u043d \u0438\u043c\u0435\u0442\u044c \u0442\u043e \u0436\u0435 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e \u0438\u043c\u0435\u043d \u0438 \u0442\u043e \u0436\u0435 \u0438\u043c\u044f (\u0431\u0435\u0437 \u0441\u0443\u0444\u0444\u0438\u043a\u0441\u0430) \u0447\u0442\u043e \u0438 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440<\/p>\n<\/li>\n<li>\n<p> \u0418\u043c\u0435\u043d\u0430 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u0434\u043e\u043b\u0436\u043d\u044b \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0438\u043c\u0435\u043d\u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430, \u043d\u043e \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u043e\u0442\u043b\u0438\u0447\u0438\u044f\u043c\u0438:<\/p>\n<ul>\n<li>\n<p> \u0411\u0435\u0437 \u0441\u0443\u0444\u0444\u0438\u043a\u0441\u0430 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430<\/p>\n<\/li>\n<li>\n<p> \u0412\u0435\u0440\u0431\u043b\u044e\u0436\u044c\u044f \u043d\u043e\u0442\u0430\u0446\u0438\u044f \u0432 \u0438\u043c\u0435\u043d\u0438 \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c \u0437\u0430\u043c\u0435\u043d\u0435\u043d\u0430 \u043d\u0430 \u0442\u0438\u0440\u0435 (CamelCase = camel-case)<\/p>\n<\/li>\n<li>\n<p>\u041d\u0438\u0436\u043d\u0435\u0435 \u043f\u043e\u0434\u0447\u0435\u0440\u043a\u0438\u0432\u0430\u043d\u0438\u0435 \u0432 \u0438\u043c\u0435\u043d\u0438 \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u0437\u0430\u043c\u0435\u043d\u0435\u043d\u043e \u043d\u0430 \u0442\u0438\u0440\u0435 (just_block = just-block)<\/p>\n<\/li>\n<li>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043f\u043e \u043f\u0440\u0430\u0432\u0438\u043b\u0430\u043c \u0432\u044b\u0448\u0435 \u0438\u043c\u044f \u0440\u0435\u0441\u0443\u0440\u0441\u0430 \u0441 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u043e\u043c \u2018Block_Theme_Main_C\u2019 \u0431\u0443\u0434\u0435\u0442 \u2018block\u2014theme&#8212;main\u2019<\/p>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h2>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f<\/h2>\n<p> \u041f\u0440\u0438\u0448\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u043f\u0435\u0440\u0435\u0439\u0442\u0438 \u043a \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043d\u0430\u0448\u0435\u0439 \u0438\u0434\u0435\u0438, \u0442.\u0435. \u043a \u043a\u043e\u0434\u0443.  <\/p>\n<p>\u041d\u0438\u0436\u0435 \u0447\u0430\u0441\u0442\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 (\u043a\u043b\u0430\u0441\u0441\u044b) \u0431\u0443\u0434\u0443\u0442 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 : \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u043e\u0435 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435, \u043a\u043e\u0434 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0438 \u043a\u043e\u0434 \u0442\u0435\u0441\u0442\u043e\u0432. \u0421\u043e\u0433\u043b\u0430\u0441\u0435\u043d \u0441 \u043b\u044e\u0434\u044c\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0433\u043e\u0432\u043e\u0440\u044f\u0442 \u0447\u0442\u043e \u0442\u0435\u0441\u0442\u044b \u0435\u0441\u0442\u044c \u043b\u0443\u0447\u0448\u0430\u044f \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f, \u043e\u0434\u043d\u0430\u043a\u043e \u043a \u0441\u0432\u043e\u0435\u043c\u0443 \u0441\u0442\u044b\u0434\u0443 \u044f \u043d\u0430\u0447\u0430\u043b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438\u0445 \u0432 \u0441\u0432\u043e\u0438\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445 \u043d\u0435\u0434\u0430\u0432\u043d\u043e, \u043f\u043e-\u044d\u0442\u043e\u043c\u0443 \u043d\u0435 \u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u043c\u043e\u0438 \u0441\u0442\u0430\u0440\u0430\u043d\u0438\u044f \u0438\u0445 \u0438\u043c\u0435\u043d\u0430 \u0438\u043b\u0438 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043c\u043e\u0433\u0443\u0442 <s>\u043f\u043e\u0432\u0435\u0440\u0433\u043d\u0443\u0442\u044c \u0432 \u0448\u043e\u043a<\/s> \u0441\u0431\u0438\u0432\u0430\u0442\u044c \u0441 \u0442\u043e\u043b\u043a\u0443, \u043f\u0440\u043e\u0441\u044c\u0431\u0430 \u043d\u0435 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c \u0431\u043b\u0438\u0437\u043a\u043e \u043a \u0441\u0435\u0440\u0434\u0446\u0443.<\/p>\n<p><strong> FIELDS_READER<\/strong><\/p>\n<p>\u0412\u0441\u0435 \u043d\u0430\u0448\u0430 \u043c\u0430\u0433\u0438\u044f \u043f\u0440\u0438 \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 \u043c\u043e\u0434\u0435\u043b\u044f\u043c\u0438 \u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430\u043c\u0438 \u0431\u0443\u0434\u0435\u0442 \u0441\u0442\u0440\u043e\u0438\u0442\u0441\u044f \u043d\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u2018get_class_vars\u2019 \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442 \u043d\u0430\u043c \u0438\u043c\u0435\u043d\u0430 \u043f\u043e\u043b\u0435\u0439 \u043a\u043b\u0430\u0441\u0441\u0430 \u0438 \u043d\u0430 \u2018ReflectionProperty\u2019 \u043a\u043b\u0430\u0441\u0441\u0435, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442 \u043d\u0430\u043c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e\u0431 \u044d\u0442\u0438\u0445 \u043f\u043e\u043b\u044f\u0445, \u0442\u0430\u043a\u0443\u044e \u043a\u0430\u043a \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u043f\u043e\u043b\u044f  (protected\/public) \u0438 \u0435\u0433\u043e \u0442\u0438\u043f. \u041c\u044b \u0431\u0443\u0434\u0435\u043c \u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0442\u043e\u043b\u044c\u043a\u043e \u043e protected \u043f\u043e\u043b\u044f\u0445.<\/p>\n<p>\u0422\u0430\u043a\u0436\u0435 \u0443\u043f\u0440\u043e\u0441\u0442\u0438\u043c \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0443\u044e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443, \u0434\u043e\u0431\u0430\u0432\u0438\u0432 \u0430\u0432\u0442\u043e\u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0445 \u043f\u043e\u043b\u0435\u0439 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e, \u044d\u0442\u043e \u0438\u0437\u0431\u0430\u0432\u0438\u0442 \u043d\u0430\u0441 \u043e\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438\u0445 \u0432 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0435 \u0432\u0440\u0443\u0447\u043d\u0443\u044e, \u0447\u0442\u043e \u043f\u0440\u0438 \u0431\u043e\u043b\u044c\u0448\u043e\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0435 \u0431\u043b\u043e\u043a\u043e\u0432 \u0441\u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0442 \u043d\u0430\u0448\u0435 \u0432\u0440\u0435\u043c\u044f.<\/p>\n<details class=\"spoiler\">\n<summary>FIELDS_READER.php <\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php  declare( strict_types=1 );  namespace LightSource\\FrontBlocksFramework;  use Exception; use ReflectionProperty;  abstract class FIELDS_READER {  \tprivate array $_fieldsInfo;  \tpublic function __construct() {  \t\t$this-&gt;_fieldsInfo = [];  \t\t$this-&gt;_readFieldsInfo(); \t\t$this-&gt;_autoInitFields();  \t}  \tfinal protected function _getFieldsInfo(): array { \t\treturn $this-&gt;_fieldsInfo; \t}  \tprotected function _getFieldType( string $fieldName ): ?string {  \t\t$fieldType = null;  \t\ttry { \t\t\t\/\/ used static for child support \t\t\t$property = new ReflectionProperty( static::class, $fieldName ); \t\t} catch ( Exception $ex ) { \t\t\treturn $fieldType; \t\t}  \t\tif ( ! $property-&gt;isProtected() ) { \t\t\treturn $fieldType; \t\t}  \t\treturn $property-&gt;getType() ? \t\t\t$property-&gt;getType()-&gt;getName() : \t\t\t''; \t}  \tprivate function _readFieldsInfo(): void {  \t\t\/\/ get protected fields without the '__' prefix  \t\t$fieldNames = array_keys( get_class_vars( static::class ) ); \t\t$fieldNames = array_filter( $fieldNames, function ( $fieldName ) {  \t\t\t$prefix = substr( $fieldName, 0, 2 );  \t\t\treturn '__' !== $prefix; \t\t} );  \t\tforeach ( $fieldNames as $fieldName ) {  \t\t\t$fieldType = $this-&gt;_getFieldType( $fieldName );  \t\t\t\/\/ only protected fields \t\t\tif ( is_null( $fieldType ) ) { \t\t\t\tcontinue; \t\t\t}  \t\t\t$this-&gt;_fieldsInfo[ $fieldName ] = $fieldType;  \t\t}  \t}  \tprivate function _autoInitFields(): void {  \t\tforeach ( $this-&gt;_fieldsInfo as $fieldName =&gt; $fieldType ) {  \t\t\t\/\/ ignore fields without a type \t\t\tif ( ! $fieldType ) { \t\t\t\tcontinue; \t\t\t}  \t\t\t$defaultValue = null;  \t\t\tswitch ( $fieldType ) { \t\t\t\tcase 'int': \t\t\t\tcase 'float': \t\t\t\t\t$defaultValue = 0; \t\t\t\t\tbreak; \t\t\t\tcase 'bool': \t\t\t\t\t$defaultValue = false; \t\t\t\t\tbreak; \t\t\t\tcase 'string': \t\t\t\t\t$defaultValue = ''; \t\t\t\t\tbreak; \t\t\t\tcase 'array': \t\t\t\t\t$defaultValue = []; \t\t\t\t\tbreak; \t\t\t}  \t\t\ttry {  \t\t\t\tif ( is_subclass_of( $fieldType, MODEL::class ) || \t\t\t\t     is_subclass_of( $fieldType, CONTROLLER::class ) ) { \t\t\t\t\t$defaultValue = new $fieldType(); \t\t\t\t}  \t\t\t} catch ( Exception $ex ) { \t\t\t\t$defaultValue = null; \t\t\t}  \t\t\t\/\/ ignore fields with a custom type (null by default) \t\t\tif ( is_null( $defaultValue ) ) { \t\t\t\tcontinue; \t\t\t}  \t\t\t$this-&gt;{$fieldName} = $defaultValue;  \t\t}  \t}  } <\/code><\/pre>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>FIELDS_READERTest.php<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"php\">&lt;?php  declare( strict_types=1 );  namespace LightSource\\FrontBlocksFramework\\Tests\\unit;  use Codeception\\Test\\Unit; use LightSource\\FrontBlocksFramework\\CONTROLLER; use LightSource\\FrontBlocksFramework\\FIELDS_READER; use LightSource\\FrontBlocksFramework\\MODEL;  class FIELDS_READERTest extends Unit {  \tpublic function testReadProtectedField() {  \t\t$fieldsReader = new class extends FIELDS_READER {  \t\t\tprotected $_loadedField;  \t\t\tpublic function __construct() {  \t\t\t\tparent::__construct();  \t\t\t}  \t\t\tpublic function getFields() { \t\t\t\treturn $this-&gt;_getFieldsInfo(); \t\t\t}  \t\t};  \t\t$this-&gt;assertEquals( [ \t\t\t'_loadedField' =&gt; '', \t\t], $fieldsReader-&gt;getFields() );  \t}  \tpublic function testIgnoreReadProtectedPrefixedField() {  \t\t$fieldsReader = new class extends FIELDS_READER {  \t\t\tprotected $__unloadedField;  \t\t\tpublic function __construct() {  \t\t\t\tparent::__construct();  \t\t\t}  \t\t\tpublic function getFields() { \t\t\t\treturn $this-&gt;_getFieldsInfo(); \t\t\t}  \t\t};  \t\t$this-&gt;assertEquals( [], $fieldsReader-&gt;getFields() );  \t}  \tpublic function testIgnoreReadPublicField() {  \t\t$fieldsReader = new class extends FIELDS_READER {  \t\t\tpublic $unloadedField;  \t\t\tpublic function __construct() {  \t\t\t\tparent::__construct();  \t\t\t}  \t\t\tpublic function getFields() {<\/code><\/pre>\n<\/div>\n<\/details>\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-322802","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/322802","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=322802"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/322802\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=322802"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=322802"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=322802"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}