ru en

Пересчет индексов Nested Set дерева в Symfony

TreeОднажды использовал Nestedset behavior в Doctrine, Symfony и столкнулся с тем, что индексы стали неверными. (Прочитать как работает Nested Set можно здесь). Случилось это, скорее всего, во время миграции - по неосторожности был исполнен низкоуровневый MySQL запрос, из-за которого не отработали ивенты Doctrine, которые пересчитывают индексы. Для того, чтобы исправить это, была написана команда, которая пересчитывает индексы. В принципе, при большом желании, можно оформить это в виде отдельного сервиса, и запустить с помощью следующей миграции. Здесь показан просто рабочий пример, как пересчитать индексы.

 

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

Загрузка файлов в Symfony

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

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

В этой заметке попытаемся показать возможные пути решения поставленной задачи, как с помощью готовых решений (VichUploaderBundle, IphpFileStoreBundle), так и с помощью собственной реализации (в контроллерах Symfony и админ классах SonataAdminBundle).

Value Object'ы у Symfony формах

DecompositionSymfony разработчики часто задаются вопросом, как заставить Symfony формы работать с value-object'ами. Давайте, для примера, представим тип Money как объект с двумя полями $amount и $currency:

class Money
{
    private $amount;
    private $currency;

    public function __construct($amount, $currency)
    {
        $this->amount = $amount;
        $this->currency = $currency;
    }

    public function getAmount() // ...
    public function getCurrency() // ...
}

Можете ли вы создать form type для этого класса без методов setAmount() и setCurrency()? В этой заметке вы научитесь этому.

Удалить дефолтный блок sonata.admin.block.admin_list у SonataAdminBundle

При использовании SonataAdminBundle и SonataBlockBundle захотелось удалить дефолтный блок. 

Толку от него мало, он просто дублирует функционал бокового меню на дашборде.

При установке SonataBlockBundle, если мы просто напишем у конфигурации:

sonata_block:
    default_contexts: [sonata_page_bundle]
    blocks: []

(в будущем будем добавлять свои блоки, но для начала просто ставим пустой массив), то отловим ошибку.

Symfony Blog Bundle

HarentiusBlogBundle - бандл для  блога/простого портала (Или сложного, если с  наследованием бандлов и расширением). Движок этого сайта.

В качестве бэкенда используется SonataAdminBundle. Реализовано:

1. Админка (WYSIWYG, ckeditor), загрузка картинок, аудио, плеер.

2. Теги, категории, архивы, облако тегов

3. Статистика

4. RSS-feed (требует доработки)

5. "Умное" кэширование всего и вся, контент отдается очень быстро

Для "успокоения души" осталось:

1. Тесты

ru en

Symfony Widgets Bundle

Widgets Bundle - бандл для легкого управления виджетами, для отображения которых нужна только клиентская часть. Включает в себя функционал как клиентской, так и админ части (добавляет админ классы для SonataAdminBundle и зависим от нее). Можно использовать (к примеру) для добавления счетчиков, баннеров, кодов различных рекламных сетей (adsense и т.д.), при этом управляем всем в одном месте (админ панель).

Был написан во время разработки этого блога.

ru en

Caching Symfony controller

При разработке этого блога пришлось изобрести очередной велосипед - Caching Symfony controller. Но сначала о том, как вообще возникла подобная задача.

Например, у меня на сайдбаре есть список категорий, список архивов и теги. Если последние получить относительно просто (одна выборка), то категории и архивы сложнее. Для получения категорий нужно выбрать деревья (категории могут быть вложенными) и подзапросами получить количество заметок в категориях (довольно монстроузно получилось, посмотреть можно здесь). Для архивов нужно пройтись по всем заметкам и составить список годов/месяцев. Действия не слишком сложные, но все равно можно избавится от их выполнения на каждом запросе.

Локализация числовых/денежных данных

При разработке более-менее крупного проекта возникает проблема с локализацией числовых/денежных данных. В этой заметке расскажу о мучениях при использовании Symfony framework, Sonata Admin Bundle и клиентской части. Но сначала о сути проблемы, так как на первый взгляд она не очень очевидная.

Итак, допустим у нас есть проект, который на стороне сервера (php/шаблонизатор) рендерит числовые/денежные данные. Они должны отображаться в соответствии с установленной локаллю. Пользователь может вводить данные (в своем представлении). При этом данные могут обрабатываться еще и на клиентской части (javascript). К примеру, в большинстве стран Европы, кроме Великобритании и Ирландии десятичный разделитель запятая, в Великобритании и Ирландии - точка. Естественно, что пользователь с Германии будет вводить данные с раздилителем - запятою.

Кастомизация формы входа (на примере FOSUserBundle)

Самый проcтой способ кастомизации формы входа FOSUserBundle - использовать механизм наследования бандлов. (С предположением, что в будущем придется модифицировать не только форму входа). Покажем пример такой кастомизации с использованием bootstrap.

Фикстуры. AliceBundle

В предыдущей заметке мы познакомились с фикстурами в Symfony framework, а также с DoctrineFixturesBundle. Хотелось бы сделать обзор еще одного полезного бандла для работы с фикстурами - AliceBundle (обертка вокруг компонента alice).

Фикстуры. DoctrineFixturesBundle

Фикстуры (англ. fixtures) - очень полезный инструмент для разработки. По сути, это просто набор тестовых данных, которые используются в dev-режиме. Для prod режима обычно не используются (для прода обычно используют Data Migrations).

Для работы с фикстурами в Symfony существует несколько удобных бандлов. Первый, базовый - DoctrineFixturesBundle, которому и посвящена эта заметка.

Configuration

При создании бандла,  который будет использоваться как библиотека (и не только), полезно будет его конфигурировать.

Конечно, можно все вынести в параметры, обойтись таким образом без конфигурации, но это будет некошерно. =)

Правильная практика описывать конфигурацию в config.yml, а часть необходимых параметров выносить в parameters.yml: