четверг, 14 июля 2011 г.

Разбиваем routing.yml на несколько файлов

Если количество роутов в вашем routing.yml уверенно перевалило за 50, то, вероятно, ориентироваться в таком файле стало трудно. Самое очевидное решение - разбить его на несколько файлов. Но, увы, в symfony1 нет такой штатной возможности. Решение несложное. Как известно, в .yml можно использовать РНР-код. Что ж, попробуем! Пишем в самом начале routing.yml:

//Подключаем файлы роутингов из папки /app/config/routing/
<?php
$dir=dirname(__FILE__).'/routing/';
$dh = opendir($dir);
while ($file = readdir($dh))
{
  if (is_dir($file))
    continue;
    
  require_once($dir.$file);
}
?>


затем создаем папку /frontend/config/routing/

затем создаем там любое количество файлов .yml, по которым распределяем наши роуты так, как нам этого хочется (переносим все роуты из routing.yml). Таким образом в rounting.yml остается только РНР-код, а все роуты структурированы по отдельным файлам.

На производительности такое решение не скажется совершенно, т.к. все yml-файлы в dev преобразовываются в РНР-код и кэшируются.

Совет: поскольку имеет значение порядок, в котором описаны роуты, именуйте файлы в соответствии с порядком их подключения:

10.blog.routing.yml
20.news.routing.yml
30.private.routing.yml
40.common.routing.yml

понедельник, 21 марта 2011 г.

How to change "csrf attack detected" message in symfony

It is proposed some methods how to change this message.

I wrote another simple one:

1. Override addCSRFProtection in BaseForm.class.php:

public function addCSRFProtection($secret = null)
  {
    parent::addCSRFProtection($secret);
    $validatorSchema=$this->getValidatorSchema();
    if (isset($validatorSchema[self::$CSRFFieldName])) 
    {
      $validatorSchema[self::$CSRFFieldName]=new myValidatorCSRFToken($validatorSchema[self::$CSRFFieldName]->getOptions());
    }
  }

2. Add new myValidatorCSRFToken.class.php with contents:

class myValidatorCSRFToken extends sfValidatorBase
{
  protected function configure($options = array(), $messages = array())
  {
    $this->addRequiredOption('token');

    $this->setOption('required', true);

    $this->addMessage('csrf_attack', 'Время сессии истекло.');
  }

  protected function doClean($value)
  {
    if ($value != $this->getOption('token'))
    {
      $exception=new sfValidatorError($this, 'csrf_attack');
      throw new sfValidatorErrorSchema($this, array($exception));
    }

    return $value;
  }
}

3. That's all :)

воскресенье, 19 декабря 2010 г.

Грабли: andWhere( id != ?, null)

Простой код

$id=null;

    $q=Doctrine_Query::create()
      ->from('sfGuardUser u')
      ->andWhere('u.id != ?',$id);
      
    print_r($q->fetchArray());

Дает совершенно неожиданные результаты:

1. SQL-запрос составляется правильный (в этом можно убедиться в дебаг-панели и в логах)

2. Результат (массив или коллекция) всегда будут пустыми.

Решение:
->andWhere('u.id != ?',(int)$id);

Вот уж не думал, что надо приводить типы в prepare_sql Доктрины!

суббота, 11 декабря 2010 г.

Как убрать поле "День" из виджета даты?

Предположим, нужно сделать виджет для выбора ГОДА+МЕСЯЦА. Проще всего для этих целей подойдет стандартный sfWidgetFormDate. Убираем у него поле для выбора дня:
$this->widgetSchema['month']->setOption('format','%month% %year%');

Но теперь сохранение формы дает ошибку Invalid на этом поле. Конечно: валидатор-то ожидает все три поля. Хорошо, не будем обманывать его ожиданий :) Дописываем в классе формы:

  function doBind(array $values)
  {
    $values['your_month_field_name']['day']=1;
    parent::doBind($values);
  }

вот и все

четверг, 9 декабря 2010 г.

Смена email пользователем

Часто в целях безопасности при регистрации пользователей их просят подтвердить свой email. Средства для генерации письма с подтверждением и экшены проверки кода подтверждения предоставляет, например, плагин sfApply. Однако, тот же плагин довольно топорно решает проблему смены email пользователем:
unset($this['email'])

Иначе говоря, все, кто хочет изменить email, идут лесом: это не разрешается. Как быть тем, кто хочет сделать более дружелюбный интерфейс?

вторник, 2 ноября 2010 г.

Отменяем кэширование CSS

Если вы часто (или хотя бы иногда!) меняете CSS-файлы фронтенда, то имеет смысл подумать над тем, чтобы не вводить в ступор пользователей, которые видят сайт в стилях, закэшированных их браузером. Иными словами, вы поменяли стили, а юзер думает "какого хрена у меня оно так выглядит?".

среда, 21 июля 2010 г.

Делаем "Направленный список чего-нибудь"

Заказчиком была поставлена следующая задача: сделать возможность создавать направленные списки (списки, в которых порядок следования элементов имеет значение), состоящие из произвольных объектов любых моделей проекта. Практическое применение: вывести в определенной последовательности 5 товаров, потом еще 10 товаров (в другой последовательности), затем 7 категорий товаров, и, наконец, 12 новостей (тоже в заранее заданной последовательности). Назовем этот список "рейтингом". Ниже представлена концепция с основными моментами реализации.

вторник, 13 июля 2010 г.

Критический баг в sfGuardPlugin

Ахтунг! Ахтунг! Метод генерации случайного ключа, используемый в sfDoctrineGuardPlugin не обеспечивает необходимый уровень случайности! Полюбуйтесь

среда, 7 июля 2010 г.

Грабли: таблицу удалили (переименовали), а она все равно создается

Если вы переименовали или удалили какую-то модель (таблицу) в доктрина-схеме, а при следующем doctrine:build эта таблица все равно создается, то надо почистить старые классы моделей (они не удаляются автоматически при изменении схемы):
symfony doctrine:clean-model-files

воскресенье, 4 июля 2010 г.

Подключаем CKEditor в Symfony

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

среда, 9 июня 2010 г.

Как использовать партиал или компонент из другого application?

Иногда возникает задача использовать партиал или компонент из другого application. Самое простое (и, на мой взгляд, логичное) решение — сделать плагин, сделать модуль, и в него положить этот партиал или компонент. Включаем модуль в settings.yml:
enabled_modules: [....., SharedComponent]

и спокойно используем его так, как будто он объявлен в папке самого application'a.

P.S. О том, как делать ссылки из одного приложения в другое, можно почитать здесь.

пятница, 4 июня 2010 г.

Обрабатываем большую коллекцию по частям

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

понедельник, 24 мая 2010 г.

Грабли: каскадное удаление в refClass'e

Чтобы избежать mysql-ошибок CONSTRAINTS при удалении/обновлении записей, которые связаны с другими связями многие-ко-многим, не забывайте прописывать каскадное удаление в ref-классах:
  relations:
    AAA:
      onDelete: CASCADE
    BBB:
      onDelete: CASCADE

суббота, 22 мая 2010 г.

Грабли: очередность загрузки фикстур

Если в папке с фикстурами лежат несколько файлов, то они обрабатываются все сразу, а по очереди. Это надо учитывать, когда создаются связи между записями в разных файлах!
Легко натолкнуться на ситуацию, когда связь не будет создана только потому, что объекта, с которым она связывает, еще нет в БД, и он неизвестен Доктрине: она до него еще просто не дошла.

Стоит отметить, что в пределах одного файла такой проблемы нет.

среда, 12 мая 2010 г.

Как взять значение фильтра из URL?

Есть сгенерированная админка. Список. Справа форма фильтрации. Как взять значение для фильтрации списка (и формы, соответственно) из URL? Очень просто.

Symfony: храним i18n-фразы в mysql

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

суббота, 8 мая 2010 г.

Грабля: значения фильтров по умолчанию

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

вторник, 20 апреля 2010 г.

Грабля: ругается, что такая запись уже есть в БД

Проблема: при редактировании объекта и отправке формы Доктрина ругается, что
An object with the same "email" already exist
при том, что мы совешенно уверены, что такой email в базе ровно один - у редактируемого объекта. В чем дело? Если случилось так, что форма редактирования объекта содержит embedded-форму, то скорее всего проблема в следующем.

Грабли: символ "-" в названии БД mysql

Не нужно использовать этот символ. Неожиданности гарантированы. Заменяйте на подчеркивание

Грабли: SQLSTATE[HY000]: General error: 1005 Can't create table

Mysql server version: 5.1.40-community
если при составлении схемы была допущена ошибка, которая привела к General error: 1005 при установке CONSTRAINTS (например примари ключ и внешний ключ имеют разные типы), то есть вероятность, что даже после исправления схемы она не сможет создаться: та же ошибка. Это связано с тем, что предыдущие, неправильно связанные таблицы, не могут удалиться: мешает кривой CONSTRAINTS. Решение одно: дропнуть БД (ну или бинарные файлы таблиц).

Лично я столкнулся с этой проблемой, когда в симфонии 1.4 случайно использовал sfDoctrineGuardPlugin из ветки 1.2. Выдалась ошибка. Заменил плагин, ошибка осталась. Удалил руками бинарники, пересобрал таблицы - все ок.