Pull to refresh

Comments 135

В оригинальной статье допущена ошибка. Этот код:


public function getLatestBlogs($limit = null)
{
    $qb = $this->createQueryBuilder('b')
               ->select('b, c')
               ->leftJoin('b.comments', 'c')
               ->addOrderBy('b.created', 'DESC');

    if (false === is_null($limit))
        $qb->setMaxResults($limit);

    return $qb->getQuery()
              ->getResult();
}

не будет корректно возвращать посты при заданном лимите, из-за того что к таблице постов джойнятся комментарии.

Точно! Распространённые грабли, в том числе среди не новичков. Поясню для тех, кто знакомится с ними впервые: чтобы получить то, что требуется ($limit блогов с комментариями), нужно сначала (отдельным запросом) выбрать айдишники нужных блогов в количестве $limit штук, а потом (вторым запросом) выбрать блоги, комментарии к ним и всё что ещё потребуется, используя ->andWhere('b.id IN :blogs_ids'), при этом не используя ни setMaxResults, ни всякие andWhere. Бандл knp_paginator берёт эту рутину на себя, его можно использовать не только для пагинации.

Я ж говорю, что фреймворки — это сплошные дырявые абстракции:
http://blog.kpitv.net/article/frameworks-1/

:)

Бред какой-то по ссылке. Даже комментировать не хочется. Не знаю кто автор, но это у него в голове сплошные дырявые абстракции.

продолжаете размахивать пиписькой? Прекращайте. В предыдущей части вы уже порядком показали что плаваете в вопросах практической реализации современных фреймворков. Иначе говоря ваши аргументы устарели.

> что плаваете в вопросах практической реализации современных фреймворков

бхахах.
зато в практическом решении задач не плаваем. в отличии от любителей обмазыватся фрейморками.
UFO landed and left these words here
Ода человека который не смог :) Эта статья мне напоминает то, как если бы вы взяли в руки молоток и уронили его себе на ногу, а потом всем рассказывали что молоток — плохой инструмент и вообще все молотки — это кошмарные инструменты :)
Я думал, Вы сами бросите ссылку на статью и на код. :)
Почему я до сих пор должен сам постить ссылку на статью?
UFO landed and left these words here

поделитесь пожалуйста примером как это красиво реализовать на симфони именно для ситуации когда нужно вывести несколько постов с лимитом, и комментарии к ним. В Yii2 есть магический метод with(), а в doctrine пока ничего подобного не нашел(возможно и не найду?)

Красиво — на мой взгляд, с помощью knp_pagination. Доктрина1 умела самостоятельно делать то, что вы от неё ожидаете, доктрина же вторая, видимо, пошла более нативным путём. К тому же никто не мешает реализовать свой with() для доктрины.

>Comments: {{ blog.comments|length }}

То есть, для того, чтобы показать количество комментов, нужно выбирать все комменты?
Гениально.

>Так как теги хранятся в базе данных в виде значений, разделенных запятыми

Явно нужна нормализация базы…

>if (false === is_null($limit))

Странное условие

>Гораздо лучший подход будет заключаться в том, чтобы отображать не дату, а время, которое прошло с момента публикации комментария

Очень спорно.

П.С.
Но все равно спасибо за руководство, так как скоро придется с этим чудом работать.
Это к тому что вы невнимательно читаете. В статье намеренно вызывается {{ blog.comments }} чтобы показать как работает ленивая загрузка и что не всегда это оптимальное решение её использовать.
padlyuck какую-то дичь сует не в тему.
Нужно думать, что лениво грузить.
Грузить все комменты для показа количества не нужно ни лениво, ни нелениво.
Гении фреймворков собрались, блин.
Всё в тему. Вы похоже не читали книг по разработке в которых намеренно написан код в котором используется неоптимальное или неправильное решение, дабы читатель сам пошевелил мозгами в поисках правильного. Вы сами не до конца понимаете что и для чего используется, судя по вашей статье выше, но уже мните себя экспертом в фреймворках, хотя прочитали только про Yii, и то его не осилили.
UFO landed and left these words here
Загрузка всех комментариев для подсчета их количества — это выстрел себе в ногу. Комментариев может быть и 10000, но это не значит что нужно их все извлекать. Ни что не мешает вместо добавления их в выборку написать в селекте count(c.id) и сгруппировать по id блога. Ну и с тегами, странно хранить их через ","… Это должна быть м2м связь между записью блога и таблицей тегов, тогда можно аналогично считать теги, группируя их
Многие, кто работал с реальными нагрузками, вообще перестают выводить количество и просто расчитывают, необходимо ли показывать следующую страницу, или нет.
> Создание блога на Symfony 2.8 lts [ Часть 5]
прямо сериал.

а могли просто поставить wordpress
Вы путаете цель и средство, в данном случае блог это не цель, а средство. Целью же тут является ознакомление с новым инструментом, на классической задаче, которая покрывает многие аспекты реальных задач из работы «Что-то типо web студии».

Сам когда-то знакомился с Django, на подобном материале, хотя и не написал в итоге ни одного блога :)
> Целью же тут является ознакомление с новым инструментом, на классической задаче, которая покрывает многие аспекты реальных задач из работы «Что-то типо web студии».

но wordpress покрывает 90% или более реальных задач из работы «Что-то типо web студии».
если б этот чудо фрймворк sympony показали на примере для чего то более серъезного — типа написания своего фейсбука. или гугола
я б дейсвительно задумался о его применении.
а так больше похоже на попытку усложнить и повысить стоимость разработки типовых задач. но зачем? если с этим справитс wordpress.
а молоток вы купите после того как им построют дом, или сколоченной табуретки будет достаточно?

Надо понимать, что написание фейсбука не зависит от фреймворка, поскольку 99,99999% кода к фреймворку отношения иметь не будет. А оставшиеся 0.00001% — реализуются на любом фреймворке одинаково.
>а молоток вы купите после того как им построют дом, или сколоченной табуретки будет достаточно?

Разжуйте, пожалуйста, свою аналогию, а то она не совсем понятна и очевидна. :)

>поскольку 99,99999% кода к фреймворку отношения иметь не будет.

Поскольку в здравом уме никто такой проект не будет писать на мейнстримовом фреймворке. Хотя фейсбук те еще клоуны.
Фейсбук на самописи?
> написание фейсбука не зависит от фреймворка, *поскольку 99,99999% кода к фреймворку отношения иметь не будет*. А оставшиеся 0.00001% — реализуются на любом фреймворке одинаково.

и вот тут то мы и приходим к заключению — что фреймворки бесполезны.
я склонен считать, что для сильно кастомного проект полезен будет микрофреймворк (конфигурация, роутинг, вьюшки). фулл-фреймворк типа симфони тоже найдет свою нишу, поскольку из коробки покрывается большинство кейсов, что удобно для среднего уровня проектов.
Плюс фреймворки все-таки написаны людьми, прочитавшими «пару» книжек по проектированию приложений в отличии от людей, познающим мир фреймворков на примере 2008 года.
UFO landed and left these words here
Для таких вещей существуют готовые решения. Тут уже спрашивали про вордпресс и т.д. и т.п. Если вы изначально делаете проект на мильёны пользователей с использованием фреймворка, то в итоге вы потихоньку будете пилить свои костыли и подпорки, и рано или поздно начнется поток негатива на первоначально принятое решение.
UFO landed and left these words here
Я где то утверждал, что для миллиона пользователей нужно брать вордпресс? Я всего лишь написал, что от фреймворка после конкретной тюнячки просто может остаться меньше 50%.
да и пробелма не в количестве пользователей, а в соотношении инфраструктурного кода и бизнес логики. когда инфраструктура лишь незначительный процент, то имеет смысл пилить её с нуля под себя. если вся бизнес логика — банальный круд, то смысл делать его руками, если фреймворк его генерит на автомате со схемы бд?

Признаюсь честно, не участвовал в проекте хотя бы на пару тысяч пользователей, где были бы тупо круды.
железо дешевое, разработка дорогая.

Как только дело начинает касаться денег, вы отказываетесь от шардинга и начинаете использовать мощные мешалки в HA или инструменты типа RAC. Машины под это дело довольно дорогие, и если есть возможность оптимизировать — необходимо оптимизировать. В недалеком прошлом закупал 8 сокетную конфигурацию о 64 ядрах в 2х экземплярах + хд + сеть. Мне бы, думаю, на (остаток жизни)x2 хватило бы. И это на x86.
На новой работе раз в 2-3 месяца приходится вбивать костыли. Да архитектура не ахти. От изначального ядра и фреймворка мало что осталось в процессе.
UFO landed and left these words here
Ок, приведите примеры «нормальных фреймворков».
Я работал на PHP только с Yii и CodeIgniter.
Готовое решение в разы трудней кастомизировать

Не повторяйтесь, я не спорю с этим утверждением.
Самопись на порядки медленней в старте

Моя работа не связанна со стартапами. Заказчику в итоге необходимо законченное решение, а не 20% для старта. Если нужно очень быстро стартануть, возьмите битрикс.
UFO landed and left these words here
Костыли на проекте на мильёны пользователей начнутся скорее на вордпрессе или подобном решении, чем на фреймворке. Плюс хороший фреймворк позволяет органично (то есть без костылей и подпорок) заменить практически любую свою компоненту на стороннюю, включая самописную, задавая по сути только интерфейсы взаимодействия компонент. Та же Symfony в чистом виде по сути не фреймворк даже, а набор инфраструктурных компонент на многие случаи жизни. Фреймворком является, например, Symfony Standard Edition, где эти компоненты определенным образом объединены, но всегда можно заменить один компонент на другой с тем же интерфейсом, исключить ненужный, добавить нужный, изменить способы соединения всех используемых компонентов. Или написать свой фреймворк из готовых компонентов.
> дело в том, что в конесте фейсбука — фреймворк это капля в море

тоже хороший пример бесполезности фрейморков.
wordpress.com пользуются милионы пользователей, там используется WordPress — который составляет не каплю в море, а именно что основу.
так же отсюда следует что WordPress вполне годится для высоконагруженных проектов.

> Тогда да, проще запилить собственный фреймворк идеально подогнаный конкретно под ваш проект. но это тоже компромис
> и сделать это можно лишь имея нормальный бюджет на разработку и время.

если сразу решать задачу на готовом инструменте, а не пилить свой фрейморк то и время и бюджет станет намного меньше.
PHP это специализированный язык для веб — поставляется с большим кол-вом функций из коробки.
Фреймворки всеголишь оборачивают всю имеющуюся функциональность в кривые абстракции
и не предоставлют никаких конкретных инструментов для решения задач.
данные абстракции в специализированных языках и не нужны вовсе (в PHP они как собаке пятая нога)
(они нужны лишь в языках типа C++ чтобы скрыть всю кривость данного языка и облегчить за счет этих костыльных абстракций программирование),

UFO landed and left these words here
> собственной реализации роутинга, собсвтенной абстракции над бд, собственными вьюхами и контроллерами, собственным контейнером

непойму нах* это все нужно — если можно через PDO запросы фигачить, ну максимум написать свой кверибилдер для сохранения загрузки объектов/массивов в десяток срок кода и выводить данные встроеным в php шаблонизатором,
сохранять каждый экшн в файл. выделять основные функции в автоматически подгружаемые классы.
использовать роутинг apache или nginx.
я уже говорил выше что php не голый язык общего назначения, чтоб поверх него была необходимость городить якобы «удобные» абстракции
там уже из коробки все нужное есть.
но все развивается по циклу — и скоро люди осознают и примут эту истину.

сcылки на крупные проекты уже давал —
wordpress.com, www.bluehost.com/wordpress-woocommerce
Экшн в файл это хорошо. А как потом на него ссылаться с шаблонов, чтобы то же меню построить? Как параметры передавать, чтобы красиво было?

Шаблоны на голом пхп опасны, особенно если верстку на движок натягивает верстальщик с базовыми навыками js, вдруг прошедший курсі Попова.
UFO landed and left these words here
>Экшн в файл это хорошо. А как потом на него ссылаться с шаблонов, чтобы то же меню построить?

О славянские боги! В чем проблема?

>Шаблоны на голом пхп опасны
Зато понятны всем!
Не берите на работу начинающих верстальщиков. Начинающие верстальщики эти ваши шаблонизаторы тем более не знают.
Разве в шаблонизаторах нельзя выполнить php код? В smarty легко. Даже без «тега» {php}
О славянские боги! В чем проблема?

Хардкод — всегда проблема.
Зато понятны всем!

Нет. Кроме того синтаксис пхп затрудняет понимание шаблонов.
Разве в шаблонизаторах нельзя выполнить php код?

В хорошем шаблонизаторе без дополнительных усилий — нет.
UFO landed and left these words here
>представьте, что ваше приложение конектится не к одной, а к нескольким десяткам бд

Это проблема?
Все разрулит построитель запросов.

>тысячами роутов

Шо вы курите?

>не на впс-ке за 5 баксов

У меня шаред хостинг держал 50К пользователей за 2 часа на самописи.

Новый рекорд уже на ВПС за 6 баксов:
115К пользователей в день, 240К хитов, 30К пользователей за час.

>на ферме в несколько сотен серверов

Какие фермы? Там никто не использует фреймворки (мейнстримовые).

>Все эти «ненужные» абстракци позволяют в итоге снизить сложность проекта.

Как по мне, только повышают.

Шо вы курите?

Сотня сущностей и для каждой хотя бы 4 операции — уже почти полтысячи.
Как по мне, только повышают.

Хорошие абстракции — понижают, лишая необходимости думать о реализации. В документации к абстракции есть всё, что нужно для её правильного использования. Кстати, абстракции — краеугольный камень минимум двух принципов из SOLID — они все пять не нравятся или только два?
>Сотня сущностей и для каждой хотя бы 4 операции — уже почти полтысячи.

Это Вы типа REST API собрались строить?
Это псевдопрограммирование.

>Хорошие абстракции — понижают

Хорошие — да.
На фреймворках — сплошные дырявые.
Мне нравился Делфи с его библиотекой.
в каждом комменте отсылки к фреймворкам, причем уже известно что вы знаете yii1 и не знаете symfony — компетенция нулевая.
зачем симфони? он даже yii2 не смотрел, а вы тут сразу на симфони замахнулись))
Это Вы типа REST API собрались строить?
Это псевдопрограммирование.


Это как псевдо?! Для вас программирование это шаблончики на сервере рендерить?

На фреймворках — сплошные дырявые.


Допустим, Symfony HttpFoundation Request — где дыры?
UFO landed and left these words here
>что наш текущий проект на yii1 держит онлайн порядка 200к единовременных пользователей, а в часы пик до 400к

Опять какой-то сервис по выборке по первичному ключу? :)
Количество единовременных как меряете? Гугл аналитикой?
UFO landed and left these words here
В догонку.
Там нифига не написано, как они тюнили.
А большинство запросов там — по первичному ключу.
Это по ходу не сайт, а какой-то сервис по отдаче данных по первичным ключам. :)
30 ms — время генерации — много.
Поддерживаю вас.
Конечно нужен строитель запросов.

+1 за роутинг на стороне вебсервера. Это его хлеб. Фреймворки проблему не там решают. Получаем оверхед.

Нарушение инкапсуляции как минимум — веб-сервер должен знать о приложении очень многое, практически о каждой его функции.
Зато можно отдельные разделы разнести на разные бекэнды :)
Нету оверхеда.
Не нужно разбираться, как строить роутинги, минус одно звено в программировании, система проще.

Что имеется в виду под «о каждой функции»?
С роутингом тоже можно, причём родным для веб-сервера способом — проксировать ссылки.
UFO landed and left these words here
Мои проекты на самописи и так влезали в шаред хостинг :)
На работе на одном из проектов 10 бекэндов.
Но балансировщик — это не дело программистов.

Балансировщик шлет трафик не по разделам на разные бекэнды.
Обычно балансировщик работает на бекэнде с http-сервером.
А так можно обойтись без http сервера.
UFO landed and left these words here
Балансировщик шлет трафик не по разделам на разные бекэнды.

Балансировщик (http) шлёт запросы как ему скажут. Скажем, запросы http://example.com/users он будет слать на один бэкенд, запросы http://example.com/posts распределять по десятку других бэкендов, а статику проксировать на CDN. И да, балансировщик, как и веб-сервер — это не дело программистов в общем случае. Но и дергать админов на каждый новый контроллер — очень быстро админы скажут, что это не их дело роутинг настраивать, будут требовать единую точку входа на приложение.
Рассмешили :)
Сейчас работаю в проекте под большой нагрузкой, где делали изначально роутинг на веб-сервере. Вышел такой некислый кусок nginx строк на 800. Прошло несколько лет, наняли SEO-оптимизатора. Интересно, вы представляете, сколько грабель было собрано на продакшене, пока отрубали банальный trailing slash в ссылках?
1. А зачем отрубать trailing slash?
2. Для перевода url на без / можно написать 1 правило.
3. У меня нет в конфиге нгинкса завязки на trailing slash. Если она у вас была, то она может быть и в роутинге на приложении.
1. Рекомендация SEO, у нас были дубликаты со слешем и без
2. Писали — наступили на грабли. Некоторые сразу увидели, некоторые спустя какое-то время
3. У нас весь роутинг в nginx, приложение получает только GET запрос.

Проблема тут не совсем в том, где роутинг изначально делался. Когда вы работаете один или в команде есть человек, который стоял у истоков и всё хорошо знает — замечательно. Но часто бывает, что проект живет больше 5 лет и люди менялись каждые полгода-год. В итоге приходит человек вроде меня и видит не то, что даже вавилонскую башню, а просто сборную солянку. И всё потому, что изначально был задан дурной тон в разработке, велосипедостроение, никакой оглядки на best practices и стандартизацию. Всё начинается с мелочей, а заканчивается «разбитыми окнами». Разобраться и навести порядок — не знаю реально ли. Уже не первый раз в такое попадаю. Раньше сваливал побыстрей.
1. И у вас в нгинксе было прописано 2 роута: с / и без? Дурота.
3. Вы говорили, что роутинг на веб-сервере — плохо. Я думал, вы перенесли его в приложение :)
1. Там куча кастомных роутов :(
3. Я бы с удовольствием перенес в приложение, но это уже сделать практически нереально, тем более тестов нет.
и не предоставлют никаких конкретных инструментов для решения задач

Если вы имеете в виду бизнес-задачи, то в точку. Фреймворки — не инструменты для решения бизнес-задач, фреймворки — инструменты для создания инструментов решения бизнес-задач, обеспечивая типовые решения для типовых инфраструктурных задач. Лучше всего они себя проявляют, когда бизнес-задачи не типовые. Если ваша бизнес-задача — создание инструмента коммуникации с клиентами в виде стандартного блога, то писать блог на фреймворке не самое оптимальное решение в общем случае. Но если решили использовать готовое решение, то надо иметь в виду, что в случае если вам стандартного блога станет мало, то кастомизация готового решения в общем случае обойдётся дольше и(или) дороже чем если бы написали на фреймворке.
С таким успехом на самописи еще лучше :)
Правда, это скорее подойдет, если вы сами разбираетесь в программировании.
На самописи, как минимум, у вас будет очень дорогой и долгий старт.
Распространенное заблуждение.
Никто ядро системы каждый раз с нуля не пишет.

Я бы и не был бы против фреймворков, если бы они были толковыми.
Но они упоротые и доставляют больше проблем, чем дают выгоды.
Никто ядро системы каждый раз с нуля не пишет.

Не пишут только те, кто используют фреймворки. Популярный или тот, о котором знает только автор — нюансы в контексте спора о том лучше писать с нуля или на фреймворке.
если б этот чудо фрймворк sympony показали на примере для чего то более серъезного — типа написания своего фейсбука. или гугола
я б дейсвительно задумался о его применении.

В общем-то, дальше уже не о чем говорить.
> я б дейсвительно задумался о его применении.
да вы не думайте, вам это вредно. продолжайте обмазываться своими самописями и всё у вас будет хорошо. главное намазывать толстым слоем.
> да вы не думайте, вам это вредно. продолжайте обмазываться своими самописями и всё у вас будет

WordPress самопись, лолчто?
~14 лет разработки и развития, сотни разработчиков ядра. c сохранением обратной совместмости,
а не переписыванием следующей мажорной версии с нуля как это любят делать во всех известных фреймворках.
Крупный коммерческий сервис wordpress.com с крупной коммерческой компанией https://en.wikipedia.org/wiki/Automattic
и многих других — есть кому вкладывать деньги в разработку и развитие, а значит это уверенность в будущем.

Вот просвещайтесь https://ru.wikipedia.org/wiki/WordPress
и еще вводная статья на хабре https://habrahabr.ru/post/282401/ для тех кто не в теме.
UFO landed and left these words here
с костылями и подпорками всё что угодно можно на всём чём угодно написать, только причем тут ваш вброс про вордпресс в теме о симфони?

з.ы. Самопись относилась не к вордпрессу, а к подходу некоторых товарищей «все фреймворки шлак, а я дартаньян»
Спасибо за серию статей. Очень подробный и полезный материал. Единственно маленькая просьба, не могли бы Вы еще одной статьей рассмотреть построение блога на Symfony со стороны пользователей? Знаю что есть бандл FOSUserBundle но не уверен можно ли его использовать или есть какие то альтернативы лучше. Спасибо.
Да, Плюсую за FOSUserBundle. Было бы интересно посмотреть на реализацию пользователей и админку(ее защиту).
За такое:
{{ render(controller('BloggerBlogBundle:Page:sidebar' ))}}
нужно бить по рукам.
зачем дергать контроллер из вьюхи?
можно просто заинклудить вьюху с сайдбаром и все.

а где делать выборки тегов и последних комментариев?

Писать кастомную Twig функцию. Ибо дергание контроллера из вьюхи слишком затратно по производительности.

Спасибо за ответ. А форму добавления комментария тоже в таком случае лучше упаковать в отдельный "виджет" или это уже будет экономия на спичках?

Форму комментария ненужно выносить в отдельный «виджет» ибо она будет не на каждой странице и ради нее не нужно дергать контроллер во вьюхе.

дело в том, что в предыдущей части статьи, форма добавления комментария выводится точно такой же конструкцией, так что в соответствии с данным мануалом контроллер по идее таки будет дергаться для вывода формы.

Вообще это (дергать контроллер из вьюхи) стандартная рекомендуемая практика:
Whenever you find that you need a variable or a piece of information that you don't have access to in a template, consider rendering a controller. Controllers are fast to execute and promote good code organization and reuse. Of course, like all controllers, they should ideally be «skinny», meaning that as much code as possible lives in reusable services.

Symfony Book

Ваше «слишком затратно» в цифрах как-то выражается?
Когда вы дергаете контроллер из вьюхи то запускается весь kernel с его зависимостями и чем их больше, тем больше просядет производительность…

Symfony Book в свою очередь содержит информацию которая призвана популяризировать фреймворк, показать что не все так сложно, поэтому не всегда в нем описывают сложные подходы.

Ради интереса я когда то делал замер, данных для вывода было немного(облако тегов). С кастомной функцией гораздо быстрее рендерится страница.
Надо отметить, что весь кернел с зависимостями уже запущен, т.к. все это происходит в рамках одного инстанса.
Но чисто сементически мне это тоже не нравится.
Семантически, по-моему, вполне ок. Основной контроллер отвечает за предоставление основного контента в ответ на запрос пользователя, передаёт в представление только одну (ну, или какой-то минимум) переменную, непосредственно отображающие данные, запрошенные пользователем. Представление на базе каких-то факторов решает отображать или нет какой-то виджет, семантически несвязанный (мало связанный) с запросом/данными. Виджету нужны данные сервисов (включая ORM), виджету нужно своё представление, виджет может зависеть от прав пользователя — где как не в отдельном контролере всё это собирать и выдавать готовый html? Вполне себе HMVC-way. Плюс, если мы решим перенести рендеринг на сторону клиента, получая данные для него аяксом, то в контроллере нужно будет изменить формат вывода для него.
>> где как не в отдельном контролере всё это собирать и выдавать готовый html

данные собирать сервисом, рендерить — вьюшкой, обернуть все это в некий компонент, не завязанный на реквест (в отличии от контроллера) — компонент слоя View (виджет yii, extension twig'а). Все-таки контроллер традиционно это что-то работающее с реквестом юзера.

Я понимаю HMVC как слоеную архитектуру с адаптерами в виде контроллеров между слоями. В php-фреймворках традиционно один контроллер, поэтому именно семантически это выглядит некорректно. То есть вынеси экшн, назови виджетом — и все довольны.

render(component(...)) это и есть вызов контроллера для получения некого ресурса. Да, у этого ресурса нет внешнего урла (а может и есть, никто не запрещает). Но он точно так же может работать с реквестом, с контейнером, генерить какие-то данные и выдаёт какой-то респонс. И это именно то, что требуется в сайдбаре. Получить ресурс "данные для сайдбара" — задача более подходящая для контроллера, нежели для твиг-функции (которая вобще-то не должна делать ничего, кроме обработки и подготовки к выводу уже поступивших данных, а тут она в БД полезет, начнёт с моделью работать).

вот именно что render(component(...)) вызов компонента, а не контроллера. вопрос именно в семантике.
вызвать render('SidebarWidget'), который является инстансом некоего WidgetRenderer'а, семантически корректнее и srp'шнее, чем рендерить контроллер (хотя обе сущности могут функционально быть очень похожи).
Все мое имхо.

В симфони2 нет компонентов. Есть только контроллеры, которые получают реквест и выдают респонс. Компонент делает ровно то же самое — на входе название компонента (урл), на выходе респонс (html), тогда вопрос: чем компонент отличается от контроллера, и коль уже есть контроллер, то зачем нужен некий компонент? В симфони1 существование компонентов было оправдано тем, что они типа более легковесные, там не проверяются права и т.п. В симфони2, видимо, посчитали этот аргумент слишком незначительным, ну или были какие-то другие причины, я не знаю. При таком решении компонент-контроллер становится более независимым, а значит, более реюзабельным и тестируемым.

компонент — это просто некая структура какой-то бОльшей структуры. Ничего конкретного я не имел в виду.

— контроллер получает данные (реквест), отдает json
— сериалайзер получает данные, отдает json

Является ли это описанием одинаковой сущности? Не отличаются ли они семантически, хоть и одинаковы функционально?

Контроллер рендерит всю страницу с помощью вьюшки. Виджет (отдельно формирующаяся часть вьюшки) рендерит часть вьюшки из вьюшки.
Экшн контроллера имеет урл, виджет не имеет.

Опять же протечка слоев — слой вьюшки запрашивает сущность из слоя контроллеров, хотя должно быть наоборот.
Все-таки не понимаю зачем вам нужна ещё одна структура под названием "компонент". Просто для того, чтобы показать, что она не самостоятельная структура, а вложенная? Ну называйте контроллеры SidebarComponent и всё :)

А если вам понадобится контроллер, который может быть доступен по урлу и может быть вставлен в виде "виджета", вы что будете делать? Ну например, форма логина, которая может быть в модальном окне и в body страницы, в зависимости от ситуации. Тут-то ваша "компонентная" логика и поломается.

Контроллер не обязан рендерить всю страницу, не пойму откуда этот стереотип. Он рендерит только то, за что отвечает (чаще всего — действительно за всю страницу целиком, но это не догма). И смысл разбиения страницы на несколько контроллеров — это делегирование ответственности.
Опять же протечка слоев — слой вьюшки запрашивает сущность из слоя контроллеров, хотя должно быть наоборот.


Вот именно. Вью говорит — у меня тут должен быть сайдбар, я хз что там за данные, нужны ли обращения к БД или не нужны, но вот ОН (контроллер) точно знает. Поэтому я сюда вставлю то, что ОН мне респонсит.
>> Все-таки не понимаю зачем вам нужна ещё одна структура под названием «компонент».

вы просто не смОтрите абстрактно на проблему. Если в симфони работает рендер контроллера из вьюшки, то это не значит, что оно верно. Я исхожу из того, что контроллер не должен таким образом рендерится, т.к. это не задача контроллера. Раз это не задача контроллера, значит, должен быть компонент, позволяющий это делать. Пусть это будет WidgetRenderer например. Ну SRP же.

>> А если вам понадобится контроллер, который может быть доступен по урлу и может быть вставлен в виде «виджета», вы что будете делать? Ну например, форма логина, которая может быть в модальном окне и в body страницы, в зависимости от ситуации. Тут-то ваша «компонентная» логика и поломается.

это другой кейс. Суть виджета: в провайдере данных и вьюшке, отображающей эти данные. Как я понимаю, new HtmlResponse((new SidebarWidget)->render()); без проблем отработает в симфони.

>> Контроллер не обязан рендерить всю страницу, не пойму откуда этот стереотип
>> Вот именно. Вью говорит — у меня тут должен быть сайдбар, я хз что там за данные, нужны ли обращения к БД или не нужны, но вот ОН (контроллер) точно знает.

Все остальное это как раз ваш стереотип, основанный на реализации виджетов в симфони.
То есть вы считаете, что в скобочках у «ОН» должно быть слово «контроллер», потому что привыкли так в симфони, а я считаю (вслед за классическим пониманием MVC из вики), что контроллер принимает данные от пользователя, и на основе бизнес-правил формирует вьюшку, а значит формирует ВЕСЬ выхлоп, а не часть. И дальше вьюшка ни с чем не общается — все свои проблемы в виде повторяющихся частей решает сама, в рамках своего слоя. Поэтому в скобочках у «ОН» должно быть все, что угодно, но только не контроллер.

Да поймите же, что в симфони2 нет разницы между компонентом и контроллером. И незачем её искусственно создавать. Во всех случаях, когда нужно проконтролировать генерацию вью, используются контроллеры. Частично или полностью, с урлом или без — это вы всё решаете каждый раз в частном порядке. Да, может быть в других системах штуки для генерации вью под названием "layout" называют "контроллерами", а штуки под названием "sidebar" называют компонентами. В симфони2 пошли другим путём. Контроллер контролирует генерацию вью. Если какому-то вью требуется для своего рендера другой вью, который контролируется кем-то, то он обращается к тому, кем оно контролируется, т.е. к контроллеру.

>> Да поймите же, что в симфони2 нет разницы между компонентом и контроллером

еще раз: компонент — это часть некоей системы. Это не понятие из мира Симфони. Компонентом может быть сервис, контроллер, виджет, рендерер, репозиторий, валидатор и так далее. Как видите видов компонентов много, а отличаются они — своей ответственностью.
$postService->findById($id) — возвращает Post
$postRepository->findById($id) — возвращает Post
Функционал и сигнатура одинаковые, а семантика и ответственность этих двух компонентов разная.

Должен быть компонент, рендерящий вьюшку на основе клиентского реквеста. Должен быть компонент, рендерящий часть вьюшки для реюзабельности. Две ответственности — два компонента.
Обоснование тем, что в симфони так, нерабочее, поскольку эта ветка началась именно с некорректности использования контроллера в качестве виджета.
Контроллер это тоже часть некой системы, и в чем отличие от компонента? Реквест — это всего лишь аргумент контроллера (он там может быть, а может и не быть).
$postService->findById($id) — возвращает Post
$postRepository->findById($id) — возвращает Post


Вот смотою и туплю, а зачем нужен $postService? Есть же репозиторий для этих целей.
Должен быть компонент, рендерящий вьюшку на основе клиентского реквеста. Должен быть компонент, рендерящий часть вьюшки для реюзабельности. Две ответственности — два компонента.


Оба на входе принимают аргументы, а на выходе — респонс для вью, и в этом заключается их ответственность, которая одинаковая в обоих случаях. Симфони не стал делить контроллеры на внутренние/внешние, вложенные/невложенные, с реквестом/без него. Контроллер должен выдать респонс. Если тебе нужен респонс, то обращайся к контроллеру. Всё остальное — повышение уровня абстрации.
>> Контроллер это тоже часть некой системы, и в чем отличие от компонента?

ни в чем. Контроллер — один из видов компонентов, принимающий клиентский реквест.

>> Реквест — это всего лишь аргумент контроллера (он там может быть, а может и не быть).

аргумент метода — это реализация на уровне языка. Реквест — это данные, присланные клиентом.
Я выше давал пример:
— контроллер получает данные (реквест), отдает json
— сериалайзер получает данные, отдает json
реализация одинаковая — смысл разный. Поэтому две разные сущности. Повторю десятый раз: SRP, семантика.

>> Вот смотою и туплю, а зачем нужен $postService? Есть же репозиторий для этих целей.

разные слои. репозиторий — слой хранилища и отдаст мне запись, если она есть. сервис проверит мои права на получение данных например, и если права есть, получит запись из репозитория.
Аналогично контроллер возвращает html, хотя на самом деле html возвращает HtmlResponse внутри контроллера.

>> Контроллер должен выдать респонс. Если тебе нужен респонс, то обращайся к контроллеру.

респонс может выдать все что угодно. Опять же сужаете. Если существует что-то, что выдает респонс, это не значит, что респонс не может выдать что-то другое. У контроллера нет прерогативы на использование респонса.

>> Оба на входе принимают аргументы

аргументы метода — это синтаксис языка. У любого метода могут быть аргументы, и это не может быть доказательством чего-либо из обсуждаемой нами плоскости.
А вот смысл этих аргументов может повлиять на многое (см. пример контроллер/сериалайзер).

Вообще мы все это обсуждаем в контексте SRP или в контексте «так уже работает — сойдет»? Из второго принципа я уже вырос — стал плюсы solid чувствовать кожей, а нюансы семантики вижу невооруженным взглядом.

Кажется, я понял в чем ваше затруднение. Вы зачем-то наделяете вещи (контроллеры, сервисы) знаниями о том, кто, откуда и зачем их вызывает. Они не должны этого знать. Контроллеру должно быть всё равно, откуда он вызывается. Ему дают аргументы (реквест, объект, что угодно) и он на основании этих аргументов строит респонс. Его не должно волновать, вызывается он функцией из вью, из kernel или ещё откуда-то.


Конечно, сервис $postService имеет право на жизнь, но не проще ли воспользоваться уже готовым кубиком voters? Соединяем repository+voter+controller и получаем ваш postService. SOLID говорите? Ну-ну. И достать, и права проверить...


И я понял как вы решаете эту проблему. Вы просто делаете более высокоуровневую надстройку над фреймворком, чтобы вам было удобнее. Увеличиваете размер кубиков. Что ж, такая стратегия имеет право на жизнь, но тогда почему симфони? Почему не Yii или не битрикс с вордпрессом? Там это уже в готовом виде.

>> Кажется, я понял в чем ваше затруднение. Вы зачем-то наделяете вещи (контроллеры, сервисы) знаниями о том, кто, откуда и зачем их вызывает. Они не должны этого знать. Контроллеру должно быть всё равно, откуда он вызывается. Ему дают аргументы (реквест, объект, что угодно) и он на основании этих аргументов строит респонс. Его не должно волновать, вызывается он функцией из вью, из kernel или ещё откуда-то.

правильно я понимаю, что если у меня есть PostSerializer, но нет PostController, то я должен реквест закинуть в PostSerializer, ведь результат будет одинаков? Кто первый тот и отдает json?
Одно и то же повторяю разными словами по кругу.

>> Конечно, сервис $postService имеет право на жизнь, но не проще ли воспользоваться уже готовым кубиком voters?

абстрагируйтесь от симфони. Я не ищу решения какой-то проблемы в своем проекте на симфони — я с вами о программировании с т.з. правильности решений.

>> SOLID говорите? Ну-ну. И достать, и права проверить…

а в чем у вас проблема с этим? вообще понятие сервисов (не сервисов симфони) сервисного слоя вам знакомо?

>> И я понял как вы решаете эту проблему. Вы просто делаете более высокоуровневую надстройку над фреймворком, чтобы вам было удобнее. Увеличиваете размер кубиков. Что ж, такая стратегия имеет право на жизнь, но тогда почему симфони? Почему не Yii или не битрикс с вордпрессом? Там это уже в готовом виде.

вот это поворот. В каком месте я надстройку то сделал? я наоборот ухожу в сторону низкоуровневости, гибкости и развязаности, создавая сущность со своей ответственностью, вместо использования контроллера, где ни попадя, лишь потому что он может вернуть html.
Мы явно говорим на разных языках. Я не хочу переходить на личности, но посоветовал бы почитать книг вообще по архитектуре приложений, какие-нибудь энтерпрайз шаблоны Фаулера, ДДД Эванса. В вас чувствуется «специалист одного фреймворка», обосновывающий все конкретной реализацией, а не логичностью.
правильно я понимаю, что если у меня есть PostSerializer, но нет PostController, то я должен реквест закинуть в PostSerializer, ведь результат будет одинаков? Кто первый тот и отдает json?
Одно и то же повторяю разными словами по кругу.


Если у вас по какой-то неведомой причине PostSerializer возвращает объект Response, то да. Но очевидно что это не так, поэтому реквест надо закидывать в PostController.
а в чем у вас проблема с этим? вообще понятие сервисов (не сервисов симфони) сервисного слоя вам знакомо?


У меня как раз с этим никаких проблем нет :)) Есть механизмы, отвечающие за извлечение записей из БД, есть механизмы, отвечающие за проверку прав. Вы повысили уровень абстрации, объединив их в один механизм, который назвали postService.
Мы явно говорим на разных языках. Я не хочу переходить на личности, но посоветовал бы почитать книг вообще по архитектуре приложений, какие-нибудь энтерпрайз шаблоны Фаулера, ДДД Эванса. В вас чувствуется «специалист одного фреймворка», обосновывающий все конкретной реализацией, а не логичностью.


Что ж, на этом и предлагаю закончить эту увлекательную дискуссию. Благодарю.
>> У меня как раз с этим никаких проблем нет :)) Есть механизмы, отвечающие за извлечение записей из БД, есть механизмы, отвечающие за проверку прав. Вы повысили уровень абстрации, объединив их в один механизм, который назвали postService.

в вашем программировании так не делают? Ваш контроллер случайно не извлекает ли из БД данные и не рендерит ли вьюшку?
Вы ведь знаете про толстые контроллеры?

>> Если у вас по какой-то неведомой причине PostSerializer возвращает объект Response, то да. Но очевидно что это не так, поэтому реквест надо закидывать в PostController.

контроллер должен вернуть строку, выводимую в браузер, консоль, выхлоп http-клиента. Остальное — вопрос реализации. Но собственно ответа вашего это не меняет. Теперь ваш сайт стал первым сайтом, у которого вместо контроллера сериалайзер.
Ок. Тогда закругляемся.
Ваш контроллер случайно не извлекает ли из БД данные и не рендерит ли вьюшку?

Именно контроллер должен привести модель в состояние готовности к обработке запроса от view. Именно контроллер создаёт представление и связывает его с моделью. Это основная ответственность контроллера — определить какой-метод какого объекта модели дернуть (при необходимости его создав или восстановив из хранилища), дернуть этот метод, определить какому представлению (при необходимости его создав) сообщить о результате (при необходимости его создав) и собственно сообщить.
это была ирония — почитайте весь наш мини-тред.

Кстати, вот подумал, если вам очень хочется иметь компоненты (мне тоже хотелось, когда я слезал со своего велосипедного фреймворка на симфони), то их можно реализовать с помощью всё тех же мастер-реквестов. Ну и психологическую обёртку над render(controller(...)), например, render_component('sidebar') :)

еще раз: компонент — общее понятие, не имеющее отношение к симфони. Симфони как и любой фреймворк состоит из компонентов различного уровня и предназначения. Я не хочу иметь компонент — я хочу, чтобы каждая сущность занималась своим делом. Аргументация вида «в симфони так» не работает.

Контроллер генерит респонс. Он занимается только этим. В чём вопрос?

serializer возвращает json, контроллер возвращает json — зачем две сущности? вопрос в этом.

Контроллер возвращает не JSON. Контроллер возвращает Response (JsonRespose, извините что я опять про симфони).

строку, генерируемую респонсом. Вы же в браузере строку видите.
https://github.com/symfony/http-foundation/blob/master/Response.php#L236
опять вы реализацию поставили выше сути. Что бы ни возвращал мой контроллер (в любой фреймворке), итогом будет строка, во чтобы она ни была обернута для целей инкапсуляции — хотя для вас это «кубик» и повышение абстракции, ведь можно просто в контроллере вывести все напрямую.

И да, в симфони также нет такого понятии как "страница", "вложенная структура" и т.п. Есть контроллеры, есть роуты, есть шаблоны. Все эти дополнительные абстракции, которые делают фреймворк более высокоуровневым, присущи другим продуктам, типа Yii. Вероятно, они даже в некоторых местах делают разработку удобнее. Но всё же, если нужен блог, то решения лучше вордпресса не найти. Симфони2 удивительный фреймворк. Он задаёт стандарты, предоставляя при этом чрезвычайно маленькие и несвязанные кубики. В Yii-подобных этого даже близко нет и не предвидится. Монолит, чрезвыйчайно кастомизируемый и чуть более современно написанный битрикс.

В классическом понимании MVC связь view:controller не один-к-одному, а многие-ко-многим, если рассматривать контроллер как обработчик единичных запросов от представления, а не всю их совокупность.

Измеряли, само собой, в prod? Каким образом? "Гораздо быстрее" — это насколько в процентах?


Кстати, говорят, на голом пхп ещё быстрее страницы рендерятся. Но фреймворк не только и не столько для скорости исполнения кода придуман. Если есть какая-то отделяемая многократно используемая часть шаблона, то для этого можно и нужно использовать render(controller(...)). А не наделять вью (да-да, кастомная функция твига это вью) несвойственными ей полномочиями.

Измерял не в prod режиме, мне важнее было понять что быстрее отработает. В дев режиме отрендерило быстрее в 4 раза.

Ну вы же понимаете, что это не показательно… Быстрее в 4 раза? Дело однозначно не в контроллере/твиг-функции, там просто неоткуда взяться такой разнице. Скорее всего вас с контроллерами что-то не то. Если у вас висят обработчики на события реквеста, проверьте, нужны ли они на ВСЕ реквесты, или же стоит ограничиться мастер-реквестами. Почти уверен, что дело в этом.

>Symfony Book в свою очередь содержит информацию которая призвана популяризировать фреймворк, показать что не все так сложно, поэтому не всегда в нем описывают сложные подходы.

Так в чем я не прав?
>Документация во всех фреймворках показалась какой-то попсовой, вроде расчитаной на дебилов (http://blog.kpitv.net/article/frameworks-1/ )

Очевидно, с такой позицией начнётся драка. У меня есть желание бить по рукам тем, кто запрещает такое по неведомым причинам.

Причина описана выше. Да никто не запрещает юзать render контроллера, как и юзать lazyLoad для вывода данных из связных таблиц. При малых обьемах данных разница будет минимальна, а вот при больших…

Озвученная причина несостоятельна. А вот с lazy load прикол (проблема) в том, что при больших количествах зависимостей между выбираемыми сущностями иногда бывает быстрее (даже в продакшене) использовать единичные доп.запросы. Потому что гидрация данных начинает сжирать какое-то невероятное время. И бывает быстрее выбрать только блоги+пользователей, а потом маленькими быстрыми запросами дополнить их телефонами+оценками+Х+Y+Z, чем выбрать сразу всё одним запросом…

Такое делается только для отношений один ко многим. Все, что идет один к одному лучше выбирать одним запросом. Для уменьшения трафика и кейса, когда никакая часть данных не может быть изменена, дополнительно указываются поля для выборки.

Всё верно, блоги+пользователи это один-к-одному, а телефоны+оценки+X+Y+Z это и есть один-ко-многим, поэтому и разделяем. Вот и приходится извращаться денормализацией и отдельными запросами. Да, проблема именно в том, что result set слишком большой, даже если в итоге всего 10 постов на странице

А-ха-ха.
Подрались и без меня.
А об этом я писал в своей статье:
«Сам подход, что запускается 1 контроллер глуп.»
«Нету возможности выполнить другой контроллер.»

Фреймворки явно с подходом «только один контроллер» для хоумпаджей.

В моей самописи «контроллеры» легкие. :)
UFO landed and left these words here

Тоже сначала так думал, но потом понадобилось сделать так:
{{ render_esi(controller('BloggerBlogBundle:Page:sidebar' )) }}

There are no tags закрывающий так лишний — он закрывается ниже
а у меня что-то ошибка General error: 1 Cannot add a NOT NULL column with default value NULL при выполнении миграции
Sign up to leave a comment.

Articles