Статические одноранговые классы Propel: как избежать дублирования кода?

У меня есть несколько таблиц, настроенных в Propel, со сгенерированными статическими классами Peer.

Моя проблема в том, что мне нужно выполнить одну и ту же операцию поиска в разных, но похожих таблицах. Эти таблицы имеют разные классы Peer, так как именно так работает Propel. Эта ситуация приводит к дублированию кода в отношении запросов, выполняемых к этим таблицам.

Мне было интересно, есть ли какая-то конструкция (избегающая использования функции eval), которая могла бы помочь мне в этом случае; Я действительно хотел бы избежать написания дублированного кода, который выполняет одни и те же точные вызовы только для разных статических классов Peer.

Пример фрагмента кода из (очень длинного) метода класса, который я пишу:

$criteria = new Criteria();
$criteria->add(FoobarPeer::CONTRACTNR,$data['contractnr']);
$result = FoobarPeer::doSelect($criteria);
if(count($result) > 1){
  throw new FoobarException("status: more than one row with the specified contractnr.");
}
if(count($result) == 0){
  // no object with given contractnr. Create new one.
  $obj = $this->factory->createORM("foobar");
  $obj->setCreatedAt(time());
} else {
  // use and update existing object.
  $obj = $result[0];
}

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

Любые идеи?

Благодарность :)


person fstab    schedule 25.06.2013    source источник


Ответы (2)


Я не совсем уверен, что полностью понимаю, о чем вы спрашиваете, но вот решение того, что, как я думаю, вы спрашиваете:

function orm_for($type) {
    return strtolower($type);
}

function peer_for($type) {
    return ucfirst($type)."Peer";
}

function exception_for($type) {
    return ucfirst($type)."Exception";
}

function query($type, $data) {
    $peer = $peer_for($type);
    $exception = $exception_for($type);
    $obj = null;
    $criteria = new Criteria();
    $criteria->add($peer::CONTRACTNR, $data["contractnr"]);
    $result = $peer::doSelect($criteria);
    if(count($result) > 1) {
        throw new $exception("status: more than one row with the specified contractnr.");
    } else if(count($result) == 0) {
        $obj = $this->factory->createORM(orm_for($type));
        $obj->setCreatedAt(time());
    } else {
        $obj = $result[0];
    }
}

Я думаю, что код говорит сам за себя. Дайте мне знать, правильно ли я интерпретировал ваш вопрос.

Живой пример (просто POC) можно найти здесь

person Tom Knapen    schedule 30.06.2013
comment
Спасибо за ваш ответ, у меня есть еще вопрос: если peer_for — это метод, определенный в объекте, как мне его вызвать? Может так?: $peer = $($obj-›peer_for($type)) - person fstab; 03.07.2013

Вы должны иметь возможность использовать поведения для достижения того, что вы пытаетесь сделать. Вы можете использовать поведение для добавления пользовательского кода к сгенерированным одноранговым объектам. См. здесь.

Помимо прочего, ваше поведение может реализовывать следующие методы:

staticAttributes()   // add static attributes to the peer class
staticMethods()      // add static methods to the peer class

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

person Luke Mills    schedule 02.07.2013