Symfony lock что за файл

Обновлено: 03.07.2024

Мне нравится работать быстро. Я хочу, чтобы наш маленький проект был доступен в продакшене как можно скорее. Вот прямо сейчас. Поскольку мы ещё ничего не сделали, начнём с развёртывания простой и понятной страницы-заглушки типа "Under construction". Вам это понравится!

Потратьте немного времени, чтобы найти в интернете наиболее подходящую, старомодную анимированную картинку с надписью "Under construction". Вот эту GIF-картинку я собираюсь использовать:

Я же вам говорил, что будет очень весело.

Инициализация проекта

Создайте новый Symfony-проект с помощью CLI-утилиты symfony , которую мы ранее установили:

Если вы посмотрите на скелет проекта в репозитории на GitHub, то заметите, что он почти пуст. Там только лишь файл composer.json . Однако в директории guestbook полно файлов. Как это вообще возможно? Ответ кроется в пакете symfony/flex . Symfony Flex — это плагин для Composer, который внедряется в процесс установки. Когда он обнаруживает пакет, который содержит так называемый рецепт, Composer выполняет его.

Основной точкой входа рецептов Symfony является файл манифеста, в котором описаны операции, которые необходимо выполнить, чтобы автоматически зарегистрировать пакет в Symfony-приложении. Вам никогда не придётся заглядывать в файл README для установки пакета Symfony. Автоматизация — ключевая особенность Symfony.

Учитывая, что Git установлен на вашем компьютере, команда symfony new также создала Git-репозиторий и сделала в нём первый коммит.

Посмотрите на структуру директорий:

Директория bin/ содержит основной скрипт командной строки console . Вы будете использовать его постоянно.

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

Директория src/ содержит весь код, который вы напишете — в ней вы будете проводить большую часть времени. По умолчанию все классы в этой директории используют пространство имён App . Это ваша рабочая директория, ваш код, ваша бизнес-логика. Symfony имеет мало общего с этим.

Директория var/ содержит кеш-файлы, логи и прочие файлы, сгенерированные приложением во время выполнения; не обращайте внимания на неё. Это единственная директория, которая должна быть доступна для записи в продакшене.

Директория vendor/ содержит все пакеты, которые установил Composer, включая и сам Symfony. Это наше секретное оружие для максимальной продуктивности. Давайте не будем изобретать велосипед, а вместо этого воспользуемся существующими библиотеками для решения сложных задач. В этой директории всем заведует Composer, поэтому ничего в ней не изменяйте.

Это всё, что вам нужно знать на данный момент.

Создание публичных ресурсов

Вы можете скачать мой GIF-файл отсюда:

Запуск локального веб-сервера

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

Запустите веб-сервер в фоновом режиме прямо из директории проекта, используя флаг -d :

Сервер запустится на первом доступном порту, начиная с 8000. Вы можете открыть сайт по ссылке из CLI:

В вашем браузере по умолчанию откроется новая вкладка, на которой будет примерно следующее:

/

Для поиска причин неполадок используйте команду symfony server:log ; эта команда в режиме реального времени выводит последние строки из логов веб-сервера, PHP и самого приложения.

Перейдите к /images/under-construction.jpg . Выглядит так же?

/images/under-construction.jpg

Довольны результатом? Теперь давайте закоммитим нашу работу:

Добавление фавиконки

Подготовка к развёртыванию в продакшене

Как насчёт развёртывания нашей работы в продакшене? Я в курсе, что у нас пока ещё нет HTML-страницы, чтобы поприветствовать пользователей. Но даже если мы просто посмотрим на маленькую картинку с надписью "under construction" в продакшене — это будет большим шагом вперёд. Ну, вы наверняка знаете этот девиз: разворачивай приложение как можно раньше и чаще.

Вы можете разместить приложение у любого провайдера с поддержкой PHP. то есть почти на всех хостингах. Но учтите несколько требований: поддержка последней версии PHP, наличие баз данных, сервера очереди и т.п.

Я сделал свой выбор: это будет SymfonyCloud. У него есть всё необходимое, а кроме этого он помогает финансировать разработку Symfony.

В консольной команде symfony есть встроенная поддержка SymfonyCloud. Давайте создадим проект в SymfonyCloud:

Эта команда создаёт несколько файлов, которые требуются для работы с SymfonyCloud: .symfony/services.yaml , .symfony/routes.yaml и .symfony.cloud.yaml .

Добавьте их в Git и закоммитьте:

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

Развёртывание в продакшене

Не пора ли нам развернуть приложение?

Создайте новый проект SymfonyCloud:

Эта команда выполняет ряд операций:

  • При первом запуске этой команды нужно пройти аутентификацию с помощью учётной записи SymfonyConnect, если вы ранее этого не сделали.
  • Команда создаст новый проект на SymfonyCloud (в течение 7 дней вы можете бесплатно разместить любой новый проект).

Наконец, разворачиваем приложение:

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

Убедитесь, что всё работает хорошо:

Вы должны получить ошибку 404, но перейдя на /images/under-construction.jpg , вы увидите GIF-изображение.

Обратите внимание, что вы не увидите стандартную красивую страницу Symfony на SymfonyCloud. Почему? Скоро вы узнаете, что Symfony поддерживает работу с несколькими окружениями, а SymfonyCloud автоматически развёрнул код в окружении продакшена.

Если вы хотите удалить проект на SymfonyCloud, воспользуйтесь командой project:delete .

После установки symfony/serializer я понял, что мой файл symfony.lock изменился:

Насколько я понимаю, он был введен с Symfony Flex, но чем он отличается от composer.lock и зачем он нужен вдобавок ко всему?

1 ответ

Я начинаю переходить к структуре Symfony Flex, но не могу найти больше информации о parameters.yml и parameters.yml.dist-ее удалили ? как теперь создавать пакеты с on install ask abount configuration details, как у нас в старых версиях ?

Я хотел бы настроить knp_doctrine_behaviors для knplabs/doctrine-behaviors следующим образом: knp_doctrine_behaviors: translatable: true но Symfony (flex) дает мне ошибку: [FileLoaderLoadException] Нет расширения, способного загрузить конфигурацию для knp_doctrine_behaviors . искал пространство.

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

Он был представлен начиная с версии Flex 1.0.34 , первоначально для устранения ошибок, подобных этой: "Configuring recipes executed twice" .

Похожие вопросы:

Я искал symfony docs и SO для объяснения того, что именно делает изменение флага debug symfony на true . Я чувствую себя глупо из-за того, что не нашел его . может ли кто-нибудь предоставить.

Я начинаю использовать Symfony Flex для начальной загрузки своего проекта и понял, что запуск composer install в первый раз генерирует файл с именем symfony.lock , для которого я не смог найти.

Сегодня мы начали получать ошибку во время сборки Herko. - Installing symfony/flex (v1.0.67): Loading from cache Plugin installation failed, rolling back - Removing symfony/flex (v1.0.67).

Я начинаю переходить к структуре Symfony Flex, но не могу найти больше информации о parameters.yml и parameters.yml.dist-ее удалили ? как теперь создавать пакеты с on install ask abount.

Я хотел бы настроить knp_doctrine_behaviors для knplabs/doctrine-behaviors следующим образом: knp_doctrine_behaviors: translatable: true но Symfony (flex) дает мне ошибку: [FileLoaderLoadException].

Я попытался найти любую документацию об использовании Symfony Flex, но пока безуспешно. Почти все документы указывают на установку bundle, использующего symfony Flex, а не на то, как создать bundle.

Вопрос : Действительно ли проект Symfony 3.4 , созданный с помощью установщика Flex, является Symfony 3.4 ? Или скорее проект Symfony 4 с 3.4 основными файлами? Полная история : Я работаю над.

Итак, я недавно обновил свой проект symfony до версии 4.3, и поскольку он вызвал проблемы, я понизил его до 4.2.9. Но, несмотря на мои усилия и различные варианты composer, он продолжает.

У меня есть проект с использованием symfony/гибкого трубопровода, в котором я не могу запустить composer install или composer update . Я также не могу создать новый проект composer с symfony/flex в.

У меня есть проект Symfony 3.4, который я пытаюсь обновить до 4.x с помощью Flex, но я падаю на первом препятствии. С выходом композитора этого многословного я предполагаю, что ответ смотрит мне.


Composer является стандартом де-факто для управления зависимостями в PHP. Он прост, эффективен и уже стал вездесущ.

Каждый знает, что при использовании Composer вы просто создаёте файл composer.json со списком зависимостей и их версий, а после запускаете composer install и всё готово.

Потом вы коммитите composer.json в ваш проект и каждый разработчик вашей команды может легко установить все небходимые зависимости запустив composer install .

Конечно мы знаем и про composer update , которая обновит установленные пакеты до последний версии (опираясь на указанные версии в composer.json ).

Это действительно просто. Но как насчёт файла composer.lock , который генерируется в корне проекта? Зачем ? И что нам с ним делать ?

А действительно ли вы знаете где находится .lock файл ?

Некоторое время назад я узнал, что проект OpenCFP не хранит файл composer.lock в репозитории. "Ну и что?!" - скажете вы, - “просто запускаем composer install и всё отлично. У нас установятся те же зависимости, верно?”

Предназначение .lock файла - записать в него непосредственно те версии, которые были установлены и под которые велась разработка и тестирование, чтобы в дальнейшем можно было их переустановить. Это означает, что если у вас в composer.json указана версия 1.* , а ваш коллега запустил composer update , которая установила 1.2.4 и закоммитил файл composer.lock , то вы, запустив composer install , получите ту же 1.2.4, даже если 1.3.0 уже вышла. Это позволяет быть уверенным, что каждый, кто работает над вашим проектом будет иметь абсолютно одинаковые версии пакетов.

Теперь вы может быть подумали: при надлежащем семантическом версионировании версия 1.3.0 (или даже 1.2.5) должна быть обратно совместимой, т.к. всё ещё удовлетворяет указанному значению 1.* и major-ная версия не изменилась. В чём же заключается сакраментальная мысль ?

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

Ещё достаточно рапространённая практика для проектов ставить в зависимостях ссылку на dev-master, что позволяет всегда иметь самые последние изменения. Это означает, что при каждом запуске composer install , но без сохранённого lock файла, composer будет устанавливать самый последний код библиотек, который будет напрямую с-pull-ен из их репозиториев.

Опять же, это проблема, если вы беспокоитесь о взломе вашего кода. И это одна из причин почему важно представлять Composer сфокусированным вокруг файла composer.lock . Это некое устройство безопасности и должно использоваться как таковое.

Install или Update?

Часто разработчики теряются когда они должны использовать install update . Как только вы начнёте думать об этом как о действиях с lock файлом, нежели как о зависимостях, всё встанет на свои места и будет более понятным.

Команда composer install делает следующее:

  • Проверяет существует ли composer.lock
  • если нет, резолвит зависимости и создаёт его
  • если composer.lock существует, устанавливает версии, указанные в нём

Команда composer update :

  • Проверяет composer.json
  • Определяет последние версии на основе указанных в этом файле
  • Устанавливает последние версии
  • Обновляет composer.lock в соответствии с установленными

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

Есть одно исключение из правила. В том случае, если вы устанавливаете что-то вроеде Zend Framework 2 Skeleton App, зависимости должны быть обновлены как только вы установили подобный каркас. Это потому, что Skeleton App является эдаким мета-приложением (карксом-примером). Соответственно в этом случае вы захотите "подтянуть" последние версии зависимостей, которые станут отправной точкой для начала разработки. Поэтому composer.lock не коммитится в репозитории подобных мета-приложений.

Выкладка (deploy)

При deploy-е приложения, имея composer.lock в вашем репозитории, вы должны использовать команду composer install . Так мы будем уверены, что на production сервере используются те же самые версии пакетов, как и при разработке. А также это значит, что Composer-у не требуется выполнять разрешение зависимостей и искать требуемые версии, что увеличивает скорость разворачивания.

Наличие файла composer.lock также обеспечивает консистентность между кластерами серверов, если вы запускаете Composer отдельно на каждой машине. Это позволяет вам развернуть новые ноды(машины) неделями или месяцами позже, не беспокоясь о несовпадении версий зависимостей.

Заключение

Как вы видите, это всё о .lock файле. Если вы задумались какую команду использовать composer install или composer update , пусть .lock файл направит вас. Если вы ассоциируете эти команды с тем, как они работают с содержимым .lock файла (а не с зависимостями) вы никогда не ошибётесь.


Прошло уже около двух лет с тех пор, как мы начали переписывать наш проект на Symfony2. Это было интересное время — работа с Symfony2+Doctrine2 была настоящим удовольствием после Битрикса. Конечно, оглядываясь назад, я понимаю, как не надо было делать, и сегодня делюсь этим с вами.

1. Не добавляйте файл composer.lock в .gitignore

Если вы пишете на Symfony, то наверняка используете Composer. Если нет — значит, что-то у вас в самом начале не заладилось.

Про странную манипуляцию с файлом composer.lock как-то говорил Рома Лапин на конференции PHP Frameworks Days в Киеве. Напомню, что файл composer.lock создается после последней успешной установки зависимостей и хранит последнее стабильное дерево зависимостей вашего приложения в точности до коммита. Это означает, что с помощью команды «composer install» вы можете откатиться до последнего стабильного состояния.

Многие разработчики почему то считают, что файл composer.lock лучше заигнорить. Мы не были исключением и сделали это, потому что в один прекрасный день у нас в зависимостях что-то поломалось — то ли при переходе на Symfony 2.3 (LTS), то ли при смене версии компонента symfony/icu.

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

2. Придерживайтесь слабой связанности бандлов и сервисов

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

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

История была примерно такая:

Есть популярный бандл SonataAdminBundle. Предполагается, что вы будете размещать admin-классы в своих бандлах примерно так:

Преимущество этого подхода в том, что если вы добавляете в свой проект бандл, который использует SonataAdminBundle, достаточно просто добавить одну строку в app/AppKernel.php — и все ваши админ классы начинают работать, и новые сущности становятся доступны для редактирования в админ-панели.

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

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

Мы приняли решение разделить фонд и медиатеку на разные сервисы. Нам теперь важно, чтобы эти сервисы были в разных git-репозиториях и работали на разных инстансах.

Сейчас я понимаю, что это будет непростая задача. Если бы мы в самом начале шли по пути слабой связности бандлов и сервисов, было бы намного проще.

3. Не плодите сущности

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

«Произведение» в нашей медиатеке — это одна из главных сущностей, которая агрегирует в себе аудио, видео и книги. Однажды нам понадобилось добавить свойство «тип произведения»: аудио, видео, книги, музыка. Это свойство используется в поиске и в админке для фильтрации.

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

Сразу стало понятно, что одним свойством тут не отделаешься. Мы решили добавить сущность Type и связать ее с произведением ассоциацией ManyToMany . Теперь, чтобы понять, какой тип проставлен в произведении, нам приходилось каждый раз перебирать типы через метод getTypes() . Также для удобства пришлось завести методы типа hasAudio() чтобы проверять, проставлен ли в произведении нужный тип.

Вызов метода getTypes() означал, что Doctrine будет делать запрос в базу данных, и это очень напрягало. Более того, пришлось также заводить фикстуры, чтобы при разворачивании проекта создавались эти типы. Страшно вспоминать :)

Немного позже, когда мне всё э то сильно надоело, я убрал эти странные сущности и просто добавил четыре булевых свойства audioType, videoType, bookType, musicType. Жить сразу стало легче.

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

4. Можно ли ваш проект развернуть в любом месте, быстро и без боли?

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

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

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

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

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

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

А есть ли возможность всегда поддерживать код приложения в порядке? Что делать, чтобы проект всегда можно было быстро развернуть в любом месте? Ответ оказался прост:

5. Используйте сервер непрерывной интеграции (CI)

Автотесты и сервер непрерывной интеграции — это темы, которые в последнее время не обсуждает только ленивый. Можно долго спорить и рассуждать на тему, нужны тесты или нет. Мы для себя решили, что нужны. Как минимум — Behat, а как максимум — PHPUnit и JS.

Самое большое преимущество CI в том, что мы можем автоматически запускать все тесты после каждого пуша в репозиторий и видеть, чей коммит всё поломал. Это особенно здорово, потому что спасает нас от деплоя бажного кода.

Кроме этого, благодаря CI вы можете поддерживать код постоянно в таком состоянии, чтобы в любой момент быстро и безболезненно развернуть приложение. Вы можете настроить всё так, чтобы сервер скачивал из репозитория последнюю версию кода, разворачивал проект на тестовом сервере и прогонял все тесты. CI на любом этапе скажет вам о проблеме, если что-то пойдет не так. Если вы сразу заметите проблему и исправите ее, то облегчите себе жизнь в будущем.

Мы остановили свой выбор на Jenkins. Настроили его таким образом, что после каждого пуша в GitHub Jenkins скачивает код последнего коммита и запускает скрипт bin/jenkins_scenario, который:
— С помощью Composer устанавливает все зависимости для проекта;
— Создает базу данных;
— Запускает миграции;
— Загружает в базу данных фикстуры;
— Запускает тесты.

6. Не игнорируйте JavaScript тесты

Этот пункт касается не только Symfony проектов. Тем не менее, сейчас я жалею о том, что мы пока так и не начали писать JavaScript тесты и не прикрутили их к Jenkins.
Behat и PHP Unit-тесты — это очень хорошо, но подчас JS тесты могут оказаться не менее важными.

Например, была ситуация, когда мы прицепили обработчик Google Analytics на кнопку для совершения пожертвования на сайте (для подсчета конверсий), но как следует не протестировали ее работу. В результате пользователи длительное время не могли жертвовать деньги, потому что эта кнопка просто не работала. Проблема обнаружилась только на следующее утро. Получилась неприятная ситуация, из-за которой фонд не дополучил деньги.

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

7. Не пишите в контроллерах служебные вещи — парсеры, скрипты для переноса данных и тому подобное

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

Мы решили для таких целей использовать контроллер с торчащим наружу URI типа «/move/authors». Мы просто открывали в браузере URI «/move/authors», и скрипт делал перенос.

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

К какому выводу мы пришли?
Лучшее решение — использовать для таких целей компонент Symfony Command. Просто запускаете на сервере нужную команду типа php app/console demo:dosomething — и ничего не будет торчать наружу.

Ещё один интересный момент, который я заметил: PHP-процесс, запущенный таким образом, работает стабильнее, чем вызов URI сайта через браузер.

8. Как вы делаете деплой?

В самом начале мы не особо беспокоились о том, как будем доставлять код на сервер. Когда он попал на Git, мы просто начали использовать для обновления команду git pull.

Конечно, для деплоймента Symfony приложения этого недостаточно. Ведь нам нужно каждый раз:
— Загружать код проекта из главного репозитория;
— Запускать миграции;
— Чистить/прогревать кеш;
— Устанавливать новые composer зависимости;
— Делать дамп css/js файлов;
— .

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

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

Когда мы начали плотно сотрудничать с этими парнями, они нас познакомили с Capifony. Это замечательный инструмент деплоймента, построенный на основе Capistrano, кастомизированный для Symfony приложений.

Несмотря на то, что установить Capifony в ubuntu/windows непросто, он может сильно упростить вам жизнь: для деплоя достаточно одной лишь команды, запущенной в терминале — cap deploy .

9. Будьте прагматичны

Представьте себе связь один-ко-многим. Один Автор может иметь много Произведений, при этом Произведение может не иметь Автора.

Route для произведения с автором выглядит так: /dostoevskiy-fedor-mihaylovich/idiot/

Без автора — так:
/bez-avtora/skazki-i-skazanija/

Генерируя путь к произведению, каждый раз придется проверять, есть ли у произведения автор, и исходя из этого выбирать нужный Route. Кроме этого, в проекте есть много страниц, в которых также должна быть ссылка на произведение, а значит, надоедливых if/else не избежать.

Однажды мой коллега предложил: «Слушай, а давай создадим „неизвестного автора“, и к нему привяжем все произведения без автора — таким образом нам будет намного легче работать со связями, роутингом и так далее?».

Мне эта идея не понравилась. Я тогда подумал: «придется писать костыли, чтобы этого неизвестного автора не показывать в списках. » Так как последнее слово было за мной, еще раз подумав, я отказался. И сейчас сильно жалею об этом. На каждом углу при разработке нам приходится делать небольшие «танцы с бубном» и писать проверки типа:

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

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

10. Не пишите код для скачивания файлов на PHP

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

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

Подобные разговоры происходили почти каждый день:


Каких только предположений и догадок у нас не было:
— «Наверное, это точно MySQL, давайте логировать медленные запросы!»
— «Смотри! У нас тут есть древовидное меню, которое использует рекурсию. Может, тут собака зарыта?»
— «А вот на главной странице отправляются 3 одновременных Ajax-запроса, может, из-за этого оверхед?»
— «Наверное, просто Doctrine слишком медленная и жрет много памяти, давай попробуем всё закешировать!»
— «Слушай, я почти уверен, что проблема из-за страницы произведения! Тут иногда создается по тысяче PHP-объектов и вообще нет пагинации!»
— «. »

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

По словам админа, наш код вообще почти не потреблял память, а более всего «стоял» в ожидании жесткий диск и забивался интернет-канал. Тут мы, кстати, начали грешить на хостинг, потому что выяснилось, что канал — всего лишь 100Mbit, и понятно, что для медиа-ресурса, с которого постоянно качают файлы, этого мало.

Тут мы решили, что вся проблема — в канале, и нам просто его не хватает. И так как мы уже тогда собирались перенести наши 3TB в облако, то решили, что после этого проблема должна уйти сама собой. Стало немного легче. Но, к нашему удивлению, сервер продолжал падать.

Как выяснялось позже, проблема была не столько в канале, сколько в тех, кто занимает пространство между ноутбуком и креслом!

We did it!

В один прекрасный день кто-то в переписке, в общем чате Skype, спросил: «А вы что-нибудь отдаете через код? Может, вы отдаете файлы для скачивания через приложение?»

Конечно! Мы отдавали файлы на скачивание через PHP. Почему? Нам нужно было, чтобы, нажимая на ссылку «скачать», пользователь получал файл, а не проигрывал его в браузере. Именно для этого мы использовали примерно такой код в контроллере:

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

Отправляемый заголовок Content-Disposition: attachment; — обычно самый типичный способ сказать браузеру, что файл нужно скачать, а не выполнить. Но когда таким образом отдаются файлы большого размера, да еще и на нагруженном проекте — память на сервере заканчивается быстро.
Мы удалили этот несчастный код и сделали так, чтобы nginx перехватывал запросы, которые содержат подстроку /download , и посылал заголовок Content-Disposition: attachment; , чтобы браузер нормально скачивал файл.

Проблема была решена.

Вместо вывода

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

Может, вы уже давно пишете на Symfony, а может, только выбираете фреймворк (кстати, недавно я писал на тему выбора фреймворка: Laravel vs Symfony) и нашли эту статью. В любом случае, думаю, наш опыт вам пригодится.

Читайте также: