оптимизация алгоритма: возвращение объекта и подобъектов из одного оператора SQL в PHP - PullRequest
0 голосов
/ 12 апреля 2010

У меня есть объектно-ориентированное PHP-приложение. У меня есть простая иерархия, хранящаяся в таблице SQL (главы и авторы, которые могут быть назначены главе).

Я написал следующий метод для извлечения глав и авторов в одном запросе, а затем перебрал результат, выяснив, какие строки принадлежат одной и той же главе, и создав объекты и главы, и массивы объектов Author.

Однако я чувствую, что это можно сделать намного аккуратнее. Может кто-нибудь помочь?

function getChaptersWithAuthors($monographId, $rangeInfo = null) {
    $result =& $this->retrieveRange(
        'SELECT mc.chapter_id, mc.monograph_id, mc.chapter_seq, ma.author_id, ma.monograph_id, mca.primary_contact, mca.seq, ma.first_name, ma.middle_name, ma.last_name, ma.affiliation, ma.country, ma.email, ma.url
        FROM monograph_chapters mc
        LEFT JOIN monograph_chapter_authors mca ON mc.chapter_id = mca.chapter_id
        LEFT JOIN monograph_authors ma ON ma.author_id = mca.author_id
        WHERE mc.monograph_id = ?
        ORDER BY mc.chapter_seq, mca.seq',
        $monographId, $rangeInfo
    );

    $chapterAuthorDao =& DAORegistry::getDAO('ChapterAuthorDAO');
    $chapters = array();
    $authors = array();
    while (!$result->EOF) {
        $row = $result->GetRowAssoc(false);
        // initialize $currentChapterId for the first row
        if ( !isset($currentChapterId) ) $currentChapterId = $row['chapter_id'];

        if ( $row['chapter_id'] != $currentChapterId) {
            // we're on a new row. create a chapter from the previous one
            $chapter =& $this->_returnFromRow($prevRow);
            // set the authors with all the authors found so far
            $chapter->setAuthors($authors);
            // clear the authors array
            unset($authors);
            $authors = array();
            // add the chapters to the returner
            $chapters[$currentChapterId] =& $chapter;

            // set the current id for this row
            $currentChapterId = $row['chapter_id'];
        }

        // add every author to the authors array
        if ( $row['author_id'] )
            $authors[$row['author_id']] =& $chapterAuthorDao->_returnFromRow($row);

        // keep a copy of the previous row for creating the chapter once we're on a new chapter row
        $prevRow = $row;
        $result->MoveNext();

        if ( $result->EOF ) {
            // The result set is at the end
            $chapter =& $this->_returnFromRow($row);
            // set the authors with all the authors found so far
            $chapter->setAuthors($authors);
            unset($authors);
            // add the chapters to the returner
            $chapters[$currentChapterId] =& $chapter;
        }
    }

    $result->Close();
    unset($result);
    return $chapters;
}

PS: методы _returnFromRow просто создают объект Chapter или Author с учетом строки SQL. При необходимости я могу опубликовать эти методы здесь.

РЕДАКТИРОВАТЬ: я не могу добавлять элементы по одному автору за один раз в главу. Мне нужно добавить их все сразу из-за структуры объекта Chapter.

1 Ответ

1 голос
/ 12 апреля 2010

Полагаю, цель состоит в том, чтобы сделать это проще и проще для понимания. Как насчет такого псевдокода? :

execute query
chapters = array()
for each result:
    chapter = result['chapter']
    author = result['author']
    if (!isset(chapters[chapter]))
        chapters[chapter] = new Chapter
    chapters[chapter].authors.append(author)

Вместо того, чтобы создавать массив авторов, заполнять его, хранить, а затем начинать заново для каждой главы, мы можем сделать код более читабельным и короче (хотя, возможно, немного медленнее). Короче говоря, для каждого результата он смотрит, находится ли глава в массиве глав. Если нет, это создает его. Затем он добавляет автора к главе.

...