public function testGroupRanges() { $r1 = new Reference(); $r1->addBookChapterAndVerseRange(1, 2, 6, 7); $r1->addBookChapterAndVerseRange(1, 2, 10, 14); $r1->addBookChapterAndVerseRange(1, 3, 2, 4); $groups = $r1->groupRanges(); $this->assertEquals(2, count($groups)); list($group1, $group2) = $groups; $this->assertEquals(2, count($group1)); $this->assertEquals(1, count($group2)); // Overlapping chapter... $r2 = new Reference(); $r2->addBookAndChapter(1, 2); $r2->addBookChapterAndVerse(1, 3, 1); $r2->addBookChapterAndVerseRange(1, 3, 7, 8); $groups = $r2->groupRanges(); $this->assertEquals(2, count($groups)); list($group1, $group2) = $groups; $this->assertEquals(1, count($group1)); $this->assertEquals(1, count($group2)); // matt+18;19.1,3,5,7 -> 18:1-19:1; 19:3,5,7 $r3 = new Reference(); $r3->addBookAndChapter(1, 18); $r3->addBookChapterAndVerse(1, 19, 1); $r3->addBookChapterAndVerse(1, 19, 3); $r3->addBookChapterAndVerse(1, 19, 5); $r3->addBookChapterAndVerse(1, 19, 7); $groups = $r3->groupRanges(); $this->assertEquals(2, count($groups)); list($group1, $group2) = $groups; $this->assertEquals(1, count($group1)); $this->assertEquals(3, count($group2)); }
/** * Generalized link formatting function, used by getLink, etc. * * Because getHandle, getTitle and getLink share common formatting * operations, they are abstracted into formatReference. * * @todo Accommodate 3-tier referencing for classical texts. * * @see getHandle, getTitle, getShortTitle * * @param string $reference * @param string $labelType HANDLE | TITLE | SHORT_TITLE * @param string $spacer Usually ' ' for title, '+' for href (handle). * @param string $delimiter Usually ':' for title, '.' for href (handle). * @return string Formatted reference string. */ public function formatReference(Reference $reference, $labelType, $spacer, $delimiter) { $r = new Reference(); // A 'group' is a set of ranges in the same chapter, or any other // single range. They start with a specified chapter. $groups = $reference->groupRanges(); // Now format each group. $formattedGroups = []; $lastBook = null; foreach ($groups as $group) { $ng = count($group); // echo "COUNT: $ng\n"; if ($ng == 0) { throw new \Exception("Groups are disordered (empty)."); } elseif ($ng == 1) { // Just one range, but it may be ANY range: show chapter // (sections not considered). list($start, $end) = reset($group); list($b1, $s1, $c1, $v1) = $r->indexToQuadruple($start); list($b2, $s2, $c2, $v2) = $r->indexToQuadruple($end); // echo "$b1, $s1, $c1, $v1\n"; // echo "$b2, $s2, $c2, $v2\n"; if ($b1 != $b2) { // Always show both book labels and chapters, // unless depth==1 and reference is whole-chapter. $book1 = $this->formatBookName($b1, $labelType); $book2 = $this->formatBookName($b2, $labelType); $depth1 = $this->getDepth($b1); $depth2 = $this->getDepth($b2); $b1Ref = null; $b2Ref = null; if ($v1 == 1 && $v2 == 999) { if ($depth2 == 1) { // No numbers $b1Ref = $book1; } elseif ($depth2 == 2) { if ($c1 == 1 && $c2 == 999) { // No numbers $b1Ref = $book1; } else { // Whole chapters $b1Ref = "{$books1}{$delimiter}{$c1}"; } } else { throw new \Exception("Book depth not found for #{$b}."); } if ($depth2 == 1) { // No numbers $b2Ref = $book2; } elseif ($depth2 == 2) { if ($c1 == 1 && $c2 == 999) { // No numbers $b2Ref = $book2; } else { // Whole chapters $b2Ref = "{$books2}{$delimiter}{$c2}"; } } else { throw new \Exception("Book depth not found for #{$b}."); } } else { // Book, Chapter(?), Verse $b1Ref = $book1 . $spacer . $this->formatVerseNumber($b1, $s1, $c1, $v1, $delimiter); $b2Ref = $book2 . $spacer . $this->formatVerseNumber($b2, $s2, $c2, $v2, $delimiter); } if ($labelType == ReferenceManager::TITLE) { $result = "{$b1Ref}-{$b2Ref}"; // or " -- " ? } else { $result = "{$b1Ref}-{$b2Ref}"; } $lastBook = $b1; } else { // $b1 == $b2 $depth = $this->getDepth($b1); $book = $this->formatBookName($b1, $labelType); $prefix = $lastBook != $b1 ? "{$book}{$spacer}" : ""; if ($depth == 1) { if ($v1 == 1 && $v2 == 999) { $result = $book; // Whole book. } else { if ($v1 == $v2) { $result = "{$prefix}{$v1}"; } else { $result = "{$prefix}{$v1}-{$v2}"; } } } elseif ($depth == 2) { $rangeNumbers = $this->formatRangeNumbers($b1, $c1, $v1, $c2, $v2, $delimiter); if (empty($rangeNumbers)) { $result = $book; // Whole book; should only occur in first occurence. } else { $result = $prefix . $rangeNumbers; } } else { throw new \Exception("Invalid book depth: {$depth}."); } $lastBook = $b1; } } else { // More than one, but known to be in the same book and chapter // (sections not considered). list($start, $end) = reset($group); list($b1, $s1, $c1, $v1) = $r->indexToQuadruple($start); $book = $this->formatBookName($b1, $labelType); $prefix = $lastBook != $b1 ? "{$book}{$spacer}" : ""; $rangeNumbers = $this->formatSingleChapterVerseRanges($group, $delimiter); $result = $prefix . $rangeNumbers; $lastBook = $b1; } $formattedGroups[] = $result; } return join(';', $formattedGroups); }