Это решение проблемы для Symfony 1.1 и Propel 1.3, когда нужно из двух таблиц объединенных черех join получить все данные. Т.е. хотим выполнить такой запрос
SELECT news.NEWS_ID, news.CATEGORY_ID, news.TITLE, news.BODY, news.CREATED_AT,
news_category.CATEGORY_ID, news_category.NAME
FROM `news`
LEFT JOIN news_category ON (news.CATEGORY_ID=news_category.CATEGORY_ID)
А вот с этим проблема, если таблицы не связаны через внешний ключ (foreign key), вывести данные из второй таблицы news_category проблематично, но возможно. В основе материал: Applying custom joins in doSelect* method. Но для новой версии материал не соответствует действительности. Чтобы все заработало, следует сделать следущее.
Рассмотрим ситуацию на примере. Есть 2-е таблицы, допустим, новости и категории новостей. Связь между таблицами через поле category_id.
Структура таблиц:
# Table "news" news_id category_id title body created_at # Table "news_category" category_id name
Мы создали модели, формы, БД:
$ symfony propel:build-model $ symfony propel:build-forms $ symfony propel:build-sql
Задача: сделать запрос и вывести все данные. Допустим сделать следующее
$c = new Criteria(); NewsPeer::addSelectColumns($c); NewsCategoryPeer::addSelectColumns($c); $c->addJoin(NewsPeer::CATEGORY_ID, NewsCategoryPeer::CATEGORY_ID, Criteria::INNER_JOIN); $news = CoreAclUserPeer::doSelect($c); # Выводим заголовок для первой записи, все отлично, а как же быть с <b>news_category.NAME</b>? echo $news[0]->getTitle();
РЕШЕНИЕ:
Нужно будет подправить несколько файлов, файлы в om и map не трогаем (напоминаю, что пример для версии симфони 1.1 и пропел 1.3):
• /lib/model/BaseNewsPeer.php
• /lib/model/BaseNews.php
BaseNewsPeer.php
# Добавляем атрибут и один метод
protected $newsCategory = null;
public static function doSelectJoinGroup(Criteria $c, $con = null, $join_behavior = Criteria::LEFT_JOIN)
{
$c = clone $c;
// Set the correct dbName if it has not been overridden
if ($c->getDbName() == Propel::getDefaultDB()) {
$c->setDbName(self::DATABASE_NAME);
}
NewsPeer::addSelectColumns($c);
$startcol = (NewsPeer::NUM_COLUMNS - NewsPeer::NUM_LAZY_LOAD_COLUMNS);
NewsCategoryPeer::addSelectColumns($c);
$c->addJoin(array(NewsPeer::CATEGORY_ID,), array(NewsCategoryPeer::CATEGORY_ID,), $join_behavior);
$stmt = BasePeer::doSelect($c, $con);
$results = array();
while ($row = $stmt->fetch(PDO::FETCH_NUM)) {
// Hydrate the News object
$omClass = NewsPeer::getOMClass();
$cls = substr('.'.$omClass, strrpos('.'.$omClass, '.') + 1);
$obj1 = new $cls();
$obj1->hydrate($row);
// Hydrate the NewsCategory object
$omClass = NewsCategoryPeer::getOMClass();
$cls = substr('.'.$omClass, strrpos('.'.$omClass, '.') + 1);
$obj2 = new $cls();
$obj2->hydrate($row, $startcol);
// Add the $obj2 (NewsCategory) to $obj1 (News)
$obj1->newsCategory = $obj2;
$results[] = $obj1;
}
return $results;
}
BaseNews.php
# добавляем метод
public function getNewsCategory()
{
if(!$this->newsCategory)
{
$this->newsCategory = NewsCategoryPeer::retrieveByPk($this->getNewsId());
}
return $this->newsCategory;
}
После это переписываем наш запрос
$c = new Criteria(); $this->userList = NewsPeer::doSelectJoinGroup($c); # Выводим заголовок для первой записи echo $news[0]->getTitle(); # Выводим название категории echo $news[0]->getNewsCategory()->getName();
P.S.
Задача решена, к БД был выполнен только один запрос.
Протестировано на Symfony 1.1.2-DEV.


