追加のクエリなしでこれを解決するために私がしたことは次のとおりです。
問題
Symfony Pager で使用される一般的な結果セットにカスタム COUNT フィールドを追加する必要がありました。しかし、私たちが知っているように、Propel はこれを最初からサポートしていません。したがって、簡単な解決策は、テンプレートで次のようにすることです。
foreach ($pager->getResults() as $project):
echo $project->getName() . ' and ' . $project->getNumMembers()
endforeach;
WheregetNumMembers()
は、オブジェクトごとに個別の COUNT クエリを実行し$project
ます。もちろん、これが非常に非効率であることはわかっています。なぜなら、表示される結果ごとにクエリを保存して、元の SELECT クエリに列として追加することで、その場で COUNT を実行できるからです。
この結果セットを表示するいくつかの異なるページがあり、すべて異なる基準を使用していました。そのため、PDO を使用して独自の SQL クエリ文字列を直接記述するのは、Criteria オブジェクトにアクセスして、そこにあるものに基づいてクエリ文字列を作成しようと試行錯誤する必要があるため、面倒です!
したがって、私が最終的に行ったことは、Propel のネイティブ コードが Criteria で動作し、通常どおり SQL を作成できるようにすることで、それをすべて回避することです。
1 - 最初に、[get/set]NumMembers() と同等のアクセサー/ミューテーター メソッドを、doSelect() によって返されるモデル オブジェクトに作成します。アクセサーはもはや COUNT クエリを実行せず、その値を保持するだけであることを思い出してください。
2 - ピア クラスに移動し、親の doSelect() メソッドをオーバーライドして、そこからすべてのコードをそのままコピーします。
3 - getMixerPreSelectHook はベース ピアのプライベート メソッドであるため、このビットを削除します (または、必要に応じてピアにコピーします)。
// symfony_behaviors behavior
foreach (sfMixer::getCallables(self::getMixerPreSelectHook(__FUNCTION__)) as $sf_hook)
{
call_user_func($sf_hook, 'BaseTsProjectPeer', $criteria, $con);
}
4 - カスタム COUNT フィールドをピア クラスの doSelect メソッドに追加します。
// copied into ProjectPeer - overrides BaseProjectPeer::doSelectJoinUser()
public static function doSelectJoinUser(Criteria $criteria, ...)
{
// copied from parent method, along with everything else
ProjectPeer::addSelectColumns($criteria);
$startcol = (ProjectPeer::NUM_COLUMNS - ProjectPeer::NUM_LAZY_LOAD_COLUMNS);
UserPeer::addSelectColumns($criteria);
// now add our custom COUNT column after all other columns have been added
// so as to not screw up Propel's position matching system when hydrating
// the Project and User objects.
$criteria->addSelectColumn('COUNT(' . ProjectMemberPeer::ID . ')');
// now add the GROUP BY clause to count members by project
$criteria->addGroupByColumn(self::ID);
// more parent code
...
// until we get to this bit inside the hydrating loop:
$obj1 = new $cls();
$obj1->hydrate($row);
// AND...hydrate our custom COUNT property (the last column)
$obj1->setNumMembers($row[count($row) - 1]);
// more code copied from parent
...
return $results;
}
それでおしまい。これで、追加の COUNT フィールドがオブジェクトに追加されました。結果を吐き出すときに別のクエリを実行してそれを取得する必要はありません。このソリューションの唯一の欠点は、親コードの途中にビットを追加する必要があるため、すべての親コードをコピーする必要があることです。しかし、私の状況では、これはすべてのクエリを保存し、独自の SQL クエリ文字列を作成しないための小さな妥協のように思えました。