symfony1.0で作っておくと良いユーティリティ

僕みたいにORM嫌いが、ORM大好きなひとのコードをリファクタリングしているときに、よくやるのがORの影響で膨大になったクエリを減らす作業です。


symfony1.0 (Propel)だと

PropelでフォルトのJOINをつかっていると気づくとレコード数×外部キーのクエリが発効され、本来10以下で済むはずのクエリが50を超えてたりします。

そんなときJOINをつかったり、WHERE〜INをつかってクエリを減らしますが、WHERE〜INを作ったり、クエリ結果をハッシュで持てるようにするときに似たようなfor分を書きまくります。

という訳でこんなのがあれば便利です。

<?php
class PropelUtil
{
  public static function arrayToPrimaryKeyMap($objects_array)
  {
    $r = array();
    if (is_array($objects_array)) foreach ($objects_array as $v) {
      if ($v instanceof Persistent) $r[$v->getPrimaryKey()] = $v;
    }
    return $r;
  }
  
  public static function getListInPrimaryKeys($objects_array)
  {
    $r = array();
    if (is_array($objects_array)) foreach ($objects_array as $v) {
      if ($v instanceof Persistent) {
        $val = $v->getPrimaryKey();
        if (!in_array($val, $r))$r[] = $val;
      }
    }
    return $r;
  }

  public static function getListInPosition($objects_array, $pos)
  {
    $r = array();
    if (is_array($objects_array)) foreach ($objects_array as $v) {
      if ($v instanceof Persistent) {
        $val = $v->getByPosition($pos);
        if (!in_array($val, $r))$r[] = $val;
      }
    }
    return $r;
  }

  public static function getListInName($objects_array, $name, $type = BasePeer::TYPE_PHPNAME)
  {
    $r = array();
    if (is_array($objects_array)) foreach ($objects_array as $v) {
      if ($v instanceof Persistent) {
        $val = $v->getByName($name, $type);
        if (!in_array($val, $r))$r[] = $val;
      }
    }
    return $r;
  }
}

1レコードずつクエリを実行されるのを防ぐためにはこうします。
ワンライナーで書きたい人はメソッド名を短くすると良いと思います

<?php
$records = Hoge::doSelect($c);

if ($records == null || count($records) == 0) return array();

$relation_tbls = PropelUtil::arrayToPrimaryKeyMap(
    FugaPeer::retrieveByPKs(PropelUtil::getListInName(
        $records, self::FKEY, BasePeer::TYPE_COLNAME)));

foreach ($records as $k => $record) {
  if (array_key_exists($record->getFkey(),$relation_tbls )) 
    $record->setRelationTable($relation_tbls[$record->getFkey()]);
  $records[$k] = $record;
}
return $records;