src/NCBS/WebsiteBundle/Controller/BibleController.php line 391

Open in your IDE?
  1. <?php
  2. namespace NCBS\WebsiteBundle\Controller;
  3. use Symfony\Component\HttpFoundation\Response;
  4. use NCBS\WebsiteBundle\Entity\Bible\Book as BibleBook;
  5. use NCBS\WebsiteBundle\Entity\Bible\Canonical\Book as CanonicalBook;
  6. use NCBS\WebsiteBundle\Tools\DataAssembly;
  7. use Skymark\UtilitiesBundle\Tools\TextFormatter;
  8. use Symfony\Component\HttpFoundation\Request;
  9. class BibleController extends NCBSWController
  10. {
  11.     protected $prefix 'Bible';
  12.     public function indexAction(Request $request)
  13.     {                 
  14.         return $this->firstbookAction($requestfalse);
  15.     }
  16.     /**
  17.      * Produces the index page for the Bible section of the website.
  18.      */
  19.     public function translationListAction(Request $request$languageCode null)
  20.     {
  21.         $this->onloadPage($request);
  22.         $locale $request->getLocale();
  23.           $nUILanguageID $this->getLanguageIDByShortCode($locale);
  24.           $translation_list null;
  25.           $sLanguageName "";
  26.           if(!empty($languageCode))
  27.           {
  28.               $aLanguage $this->getLanguageByBibliographicCode($languageCode);
  29.               
  30.               if(!empty($aLanguage))
  31.               {
  32.                   $sLanguageName $aLanguage['name'];                  
  33.                   $translation_list $this->getBibleTranslationListForLanguage($aLanguage['id']);
  34.               }    
  35.           }
  36.           
  37.           if(empty($translation_list))
  38.           {
  39.               $translation_list $this->getBibleTranslationListByLanguage($nUILanguageID);
  40.           }
  41.       //  $language = $this->getRepository('Language')->findOneByBibliographicCode($languageCode);
  42.        // $translations = $this->getRepository('Bible\Translation')->getByLanguageOrAll($language);
  43.         return $this->renderView('index', array(
  44.             'translation_list' => $translation_list,
  45.             'language_name' => $sLanguageName
  46.          //   'illustration' => $this->getRepository('Media\Image')->findOneByFile('Still_life_with_Bible.jpg')
  47.         ));
  48.     }
  49.     function getManager() {
  50.         return $this->getDoctrine()->getManager();
  51.     }
  52.     protected function getTranslationByUrl($translationUrl$request$setCurrentLanguage false)
  53.     {
  54.         //s33: cleanup
  55.         //error_log("2200 gTBU - this is a " . ClassName::class );
  56.         $em $this->getDoctrine()->getManager();
  57.         // $em = $this->getContainer()->get('doctrine.orm.entity_manager');
  58.         $bt $em->getRepository('NCBSWBundle:Bible\\Translation');
  59.         if ( ) {
  60.             // old
  61.             $translation $this->bibleData('Translation')->findOneBy(array('url' => $translationUrl'enabled' => true));
  62.         } else {
  63.             $translation $bt->findOneBy(array('url' => $translationUrl'enabled' => true));
  64.         }
  65.         if($translation !== null && $setCurrentLanguage) {
  66.             $request->getSession()->set('current_language'$translation->getLanguage()->getBibliographicCode());
  67.         }
  68.         return $translation;
  69.     }
  70.     
  71.     protected function getTranslationByUrlNoOption($translationUrl)
  72.     {
  73.         $translation $this->bibleData('Translation')->findOneBy(array('url' => $translationUrl'enabled' => true));        
  74.         return $translation;
  75.     }
  76.     
  77.     protected function getTranslationByID($translationID$setCurrentLanguage false$request)
  78.     {
  79.         $translation $this->bibleData('Translation')->findOneBy(array('id' => $translationID'enabled' => true));
  80.         if($translation !== null && $setCurrentLanguage) {
  81.             $request->getSession()->set('current_language'$translation->getLanguage()->getBibliographicCode());
  82.         }
  83.         return $translation;
  84.     }
  85.     /**
  86.      * Produces the main page for a given Bible translation.
  87.      * $userSelected is true if the user specifically chose to view this translation, false if it was chosen for the user (e.g. as a site default)
  88.      */
  89.     public function translationAction($translationUrlRequest $request$userSelected true)
  90.     {
  91.         $this->onloadPage($request);
  92.         $msgData $this->checkBibleTranslationMsg($translationUrl); 
  93.           if(!empty($msgData))
  94.           {
  95.               $response = new Response();
  96.             $response->setStatusCode(404);
  97.               return $this->renderView('no_content'$msgData$response);
  98.           }
  99.           
  100.             $translation $this->getTranslationByUrl($translationUrl$request$userSelected);          
  101.                   
  102.           $response null;
  103.         if(empty($translation)) {
  104.             $response = new Response();
  105.             $response->setStatusCode(404);
  106.             return $this->renderView('no_content', array(), $response);
  107.         }
  108.          
  109.           $nTranslationID $translation->getId();      
  110.           $book_list $this->getBibleBookList($request$nTranslationID);        
  111.             
  112.         // Don't show stories now (6/17/2022)
  113.         $suggested = array();        
  114.       //  $suggested = $this->getStoriesForTranslation($translation->getId(), 4);
  115.        
  116.         $renderView $this->renderView('translation', array(         
  117.             'book_list' => $book_list,
  118.             'suggested_stories' => $suggested,
  119.           //  'translations_by_language' => $this->getBibleTranslationsByLanguage(),
  120.             'translation' => $translation
  121.         ), $response);
  122. //    $this->logtime(" T:translationAction generated rendering");
  123.     // lastly, we cache for next time
  124. //    $memcache->save($cacheKey, $renderView, $this->getCacheTime());
  125. //    }
  126.     return $renderView;
  127.     }
  128.     function getCacheTime()
  129.     {
  130.       $cd 1800;
  131.       try {
  132.     $cd $this->container->getParameter('cache_duration');  // see this is not actually catchable ?
  133.     // $this->logtime(" T:from params, got:  $cd cache_duration");
  134.       } catch (Symfony\Component\DependencyInjection\Exception\InvalidArgumentException $e) {
  135.     $this->logtime(" T: getParameter FAIL! default  $cd cache_duration");
  136.       }
  137.       return $cd;
  138.     }
  139.     
  140.     /**
  141.      * Show the first bible book page.
  142.      * $userSelected is true if the user specifically chose to view this translation, false if it was chosen for the user (e.g. as a site default)
  143.      */
  144.     public function firstbookAction(Request $request$userSelected true)
  145.     {
  146.        // $translation = $this->getTranslationByID($translationID, $userSelected, $request);
  147.         $translation $this->getFirstBibleTranslation($request);
  148.         
  149.         $response null;
  150.         if(empty($translation)) {
  151.             $response = new Response();
  152.             $response->setStatusCode(404);
  153.         }
  154.         
  155.         return $this->redirect($this->get('router')->generate('bible_book', array(
  156.                         'translationUrl' => $translation['url'],
  157.                         'bookUrl' => $translation['book_url'],
  158.                       //  'sp' => true // show popup
  159.                     )), 301);  
  160.  /*       return $this->renderView('firstbook', array(
  161.             'translation' => $translation
  162.         ), $response);   */     
  163.     }
  164.     
  165.     /**
  166.      * Produces the page for a given Bible translation's information.
  167.      * $userSelected is true if the user specifically chose to view this translation, false if it was chosen for the user (e.g. as a site default)
  168.      */
  169.     public function infoAction($translationUrlRequest $request$userSelected true)
  170.     {
  171.         $this->onloadPage($request);
  172.         $msgData $this->checkBibleTranslationMsg($translationUrl); 
  173.           if(!empty($msgData))
  174.           {
  175.               $response = new Response();
  176.             $response->setStatusCode(404);
  177.               return $this->renderView('no_content'$msgData$response);
  178.           }
  179.           
  180.         $translation $this->getTranslationByUrl($translationUrl$request$userSelected);
  181.         
  182.         $response null;
  183.         if($translation === null) {
  184.             $response = new Response();
  185.             $response->setStatusCode(404);
  186.         }
  187.         return $this->renderView('info', array(
  188.             'translation' => $translation,
  189.      //       'translations_by_language' => $this->getBibleTranslationsByLanguage(),
  190.             'translation_info' => '1'        
  191.         ), $response);
  192.     }
  193.     protected function getBookByUrl($translationUrl$bookUrl$request$setCurrentLanguage false)
  194.     {
  195.         $translation $this->getTranslationByUrl(TextFormatter::urlify($translationUrl), $request$setCurrentLanguage);
  196.         if($translation === null) {
  197.             return null;
  198.         }
  199.         return $this->bibleData('Book')->getOneByUrlFromTranslation(TextFormatter::urlify($bookUrl), $translation);
  200.     }
  201.     
  202.     /**
  203.      * Produces the chapter list for a particular book.
  204.      * $userSelected is true if the user specifically chose to view this translation, false if the translation was chosen for the user (e.g. as a site default)
  205.      */
  206.     public function bookAction($translationUrl$bookUrlRequest $request$userSelected true)
  207.     {
  208.         $this->onloadPage($request);
  209.         $book $this->getBookByUrl($translationUrl$bookUrl$request$userSelected);
  210.         $response null;
  211.         if($book === null) {
  212.             $response = new Response();
  213.             $response->setStatusCode(404);
  214.         }
  215.         return $this->renderView('book', array(
  216.             'book' => $book,
  217.             'chapters' => $this->bibleData('Chapter')->getByBook($book),
  218.             'translations_by_language' => $this->getBibleTranslationsByLanguage($book->getCanonicalization()->getId()),
  219.         'left_to_right' => $this->isRightToLeft($translationUrl)
  220.         ), $response);
  221.     }
  222.     /**
  223.      * $userSelected is true if the user specifically chose to view this translation, false if the translation was chosen for the user (e.g. as a site default)
  224.      */
  225.     public function chapterRangeAction($translationUrl$bookUrl$chapterStartIndex$chapterEndIndexRequest $request$verseStartIndex null$verseEndIndex null$userSelected true)
  226.     {
  227.         $this->onloadPage($request);
  228.         $msgData $this->checkBibleTranslationMsg($translationUrl); 
  229.           if(!empty($msgData))
  230.           {
  231.               $response = new Response();
  232.             $response->setStatusCode(404);
  233.               return $this->renderView('no_content'$msgData$response);
  234.           }    
  235.     
  236.         if($chapterStartIndex == $chapterEndIndex) {
  237.             if($verseStartIndex === null || $verseEndIndex === null) {
  238.                 return $this->chapterAction($translationUrl$bookUrl$request$chapterStartIndex);
  239.             } else {
  240.                 return $this->verseRangeAction($translationUrl$bookUrl$chapterStartIndex$request$verseStartIndex$verseEndIndex);
  241.             }
  242.         }
  243.     $right_to_left $this->isRightToLeft($translationUrl);
  244.         $chapterRangeData = array(
  245.             'book' => $this->getBookByUrl($translationUrl$bookUrl$request$userSelected),
  246.         'right_to_left' => $right_to_left
  247.         );
  248.         if($verseStartIndex === null) {
  249.             $chapterRangeData['content_class'] = 'chapter';
  250.             $chapterRangeData['range_name'] = $this->get('translator')->trans("bible.chapternav.bookchapterrange", array(
  251.                 '%bookname%' => $chapterRangeData['book']->getName(),
  252.                 '%chapterstart%' => $chapterStartIndex,
  253.                 '%chapterend%' => $chapterEndIndex
  254.             )); 
  255.             
  256.             $chapterRangeData['slider_url'] = $this->get('router')->generate('bible_slider_chapter_range', array(
  257.                 'translationUrl' => $translationUrl,
  258.                 'bookUrl' => $bookUrl,
  259.                 'chapterStartIndex' => $chapterStartIndex,
  260.                 'chapterEndIndex' => $chapterEndIndex
  261.             ));
  262.         } else {
  263.             $chapterRangeData['content_class'] = 'verse';
  264.             $chapterRangeData['range_name'] = $this->get('translator')->trans("bible.chapternav.bookchapterrangeverserange", array(
  265.                 '%bookname%' => $chapterRangeData['book']->getName(),
  266.                 '%chapterstart%' => $chapterStartIndex,
  267.                 '%chapterend%' => $chapterEndIndex,
  268.                 '%versestart%' => $verseStartIndex,
  269.                 '%verseend%' => $verseEndIndex
  270.             ));
  271.             
  272.             $chapterRangeData['slider_url'] = $this->get('router')->generate('bible_slider_chapter_verse_range', array(
  273.                 'translationUrl' => $translationUrl,
  274.                 'bookUrl' => $bookUrl,
  275.                 'chapterStartIndex' => $chapterStartIndex,
  276.                 'chapterEndIndex' => $chapterEndIndex,
  277.                 'verseStartIndex' => $verseStartIndex,
  278.                 'verseEndIndex' => $verseEndIndex
  279.             ));
  280.         }
  281.         
  282.     // if range from start to end is >= 2, redirect to something shorter.
  283.     // We don't need to redirect now as the speed of the pages has been improved (5/15/2018)
  284.     // We decided to limit the range to 3 chapters maximum to avoid some errors. (7/19/2019).
  285.     // Changed to allow up to 8 chapters (6/21/2024)
  286.     $nMaxChapter 4;
  287.     if ( $chapterEndIndex $chapterStartIndex >= $nMaxChapter ) {
  288.       $oldEnd $chapterEndIndex;
  289.       $chapterEndIndex $chapterStartIndex+$nMaxChapter-1;
  290.       //$verseEndIndex = null;
  291. //      error_log("chapterRangeAction: //$chapterStartIndex-$oldEnd/ too large a range, redirecting to /$translationUrl/$bookUrl/$chapterStartIndex-$chapterEndIndex/");
  292.       return $this->redirect($this->get('router')->generate('bible_chapter_range',
  293.                  array( 'translationUrl' => $translationUrl'bookUrl' => $bookUrl'chapterStartIndex' => $chapterStartIndex,
  294.                     'chapterEndIndex' => $chapterEndIndex,
  295.                     // 'verseStartIndex' => $verseStartIndex, 'verseEndIndex' => $verseEndIndex -- _verse
  296.                     )), 301);
  297.     } 
  298.         $chapterRangeData['contents'] = DataAssembly::getVerseRangeFromBook($chapterRangeData['book'], $chapterStartIndex$chapterEndIndex$verseStartIndex$verseEndIndex);
  299.         $chapterRangeData['translation_url'] = $translationUrl;
  300.        
  301.         $chapterRangeData['bible_column_spec'] = $this->getMultiColumnSpecForChapterRange($translationUrl$bookUrl$chapterStartIndex$chapterEndIndex$verseStartIndex$verseEndIndex);
  302.         
  303.         return $this->createChaptersView($chapterRangeData$request);
  304.     }
  305.     // Creates multi-chapter view for access via both canonical and translation-specific numbering
  306.     protected function createChaptersView($chapterRangeData$request)
  307.     {
  308.         $this->checkIfOnMobile($request);
  309.         $response null;
  310.         if(empty($chapterRangeData['contents'])) {
  311.             $response = new Response();
  312.             $response->setStatusCode(404);
  313.               return $this->renderView('no_content', array(), $response);
  314.         }
  315.     
  316.         $allVerses array_reduce($chapterRangeData['contents'], 'array_merge', array());
  317.         $aVerseInfo $this->getVerseInfo($allVerses);
  318.         if($chapterRangeData['content_class'] !== 'storytext') {          
  319.          // $chapterRangeData['verse_story'] = $this->getStoriesForVerses($aVerseInfo, $request);
  320.         }
  321.         
  322.         $bInframe = (isset($versesData['in_frame']) && $versesData['in_frame']);
  323.         $chapterRangeData['has_slider_item'] = $this->hasSliderItem($aVerseInfo$bInframe$request, ($chapterRangeData['content_class'] == 'chapter'));
  324.                
  325.         $aOTLE $this->getOTLERefForBible($aVerseInfo, array(), true);  
  326.     //    $chapterRangeData['otle_ref'] = $aOTLE['otle_nonmusic'];   
  327.         $chapterRangeData['otle_ref_music'] = $aOTLE['otle_music']; 
  328.         $chapterRangeData['explained_verse'] = $this->getFirstExplainedVerse($aVerseInfo$request);
  329.         
  330.         $nCBookID $chapterRangeData['book']->getCanonicalization()->getId();
  331.         $nChapterStartOrder $allVerses[0]->getChapter()->getOrdering();
  332.         $nChapterEndOrder end($allVerses)->getChapter()->getOrdering();
  333.         $nVerseStartOrder $allVerses[0]->getIndexDisplay();
  334.         $nVerseEndOrder end($allVerses)->getIndexDisplay();
  335.         
  336.         $chapterRangeData['cbook_id'] = $nCBookID;
  337.         $chapterRangeData['chapter_start_order'] = $nChapterStartOrder;
  338.         $chapterRangeData['chapter_end_order'] = $nChapterEndOrder;
  339.         $chapterRangeData['verse_start_order'] = $nVerseStartOrder;
  340.         $chapterRangeData['verse_end_order'] = $nVerseEndOrder;
  341.                   
  342.         $locale $request->getLocale();
  343.           $nUILanguageID $this->getLanguageIDByShortCode($locale);  
  344.         $chapterRangeData['translations_by_language'] = $this->getBibleTranslationsByLanguageForVerses($nCBookID$nChapterStartOrder$nVerseStartOrder$nChapterEndOrder$nVerseEndOrder$nUILanguageID);
  345.          
  346.         if(!array_key_exists('canonical_chapter_start'$chapterRangeData)) {
  347.             $canonicalRangeData DataAssembly::getVerseNumberRange(DataAssembly::canonicalize($chapterRangeData['contents']));
  348.             if($canonicalRangeData !== null) {
  349.                 $chapterRangeData['canonical_chapter_start'] = $canonicalRangeData['chapter_start'];
  350.                 $chapterRangeData['canonical_chapter_end'] = $canonicalRangeData['chapter_end'];
  351.                 $chapterRangeData['canonical_verse_start'] = $canonicalRangeData['verse_start'];
  352.                 $chapterRangeData['canonical_verse_end'] = $canonicalRangeData['verse_end'];
  353.             }
  354.         }
  355.         
  356.         $chapterRangeData['text_style_override'] = $this->getTextStyleOverrideForBible($chapterRangeData['book']->getId());        
  357. //        $chapterRangeData['book_list'] = $this->getBibleBookList($chapterRangeData['book']->getTranslation()->getId());
  358.         
  359.         $chapterRangeData['verses_concept'] = $this->getVerseContentWithConceptLinks($request$allVerses$chapterRangeData['bible_column_spec']);
  360.         
  361.         $chapterRangeData['book_url'] = $chapterRangeData['book']->getUrl();
  362.         $chapterRangeData['chapter_index'] = $aVerseInfo['FirstChapterIndex'];
  363.         return $this->renderView('chapter_range'$chapterRangeData$response);
  364.     }
  365.     /**
  366.      * $userSelected is true if the user specifically chose to view this translation, false if the translation was chosen for the user (e.g. as a site default)
  367.      */
  368.     public function chapterAction($translationUrl$bookUrlRequest $request$chapterIndex 1$userSelected true$inFrame false)
  369.     {
  370.         $this->onloadPage($request);
  371.         $msgData $this->checkBibleTranslationMsg($translationUrl); 
  372.       if(!empty($msgData))
  373.       {
  374.           $response = new Response();
  375.         $response->setStatusCode(404);
  376.           return $this->renderView('no_content'$msgData$response);
  377.       }    
  378.       
  379.       $language_id $this->getLanguageIDByBibleTrans($translationUrl);
  380.                
  381.       $chapterData $this->getChapterPath($translationUrl$bookUrl$chapterIndex$request$userSelected);
  382.       
  383.       $response null;
  384.       
  385.         if($chapterData['chapter'] === null) {   
  386.             $nFirstChapterOrder $this->getFirstBibleChapterOrder($translationUrl$bookUrl);        
  387.             if($nFirstChapterOrder != null)
  388.             {
  389.                  return $this->redirect($this->get('router')->generate('bible_chapter', array(
  390.                         'translationUrl' => $translationUrl,
  391.                         'bookUrl' => $bookUrl,
  392.                         'chapterIndex' => 1
  393.                     )), 301);  
  394.             }    
  395.         } 
  396.         
  397.       if($chapterData['chapter'] === null) {
  398.            $response = new Response();
  399.             $response->setStatusCode(404);
  400.             return $this->renderView('no_content', array(), $response);  
  401.         }        
  402.           
  403.       $chapterData['verses'] = $this->bibleData('Verse')->getByChapter($chapterData['chapter']);             
  404.       $chapterData['content_class'] = 'chapter';
  405.       $chapterData['chapter_index'] = $chapterIndex;
  406.       $chapterData['right_to_left'] = $this->isRightToLeft($translationUrl);
  407.       $chapterData['content_type'] = 'verseRange';
  408.       $chapterData['translation_url'] = $translationUrl;
  409.                   
  410.       $chapterExplanations null;
  411.       $nCChapterID null;
  412.       $request->getSession()->set('current_explanation_cchapter_id''');
  413.       if($this->showBibleChapterSummary($language_id) && $chapterData['chapter']->getCanonicalization() != null)
  414.       {
  415.           $nCChapterID $chapterData['chapter']->getCanonicalization()->getId();
  416.           $chapterExplanations $this->getChapterExplanation($nCChapterID$translationUrl$request); 
  417.                     
  418.           $nExplainChapterTranslationID $this->getExplainChapterTranslation($nCChapterID$this->getCurrUserID($request), $translationUrl);        
  419.           if($nExplainChapterTranslationID > -1)
  420.           {
  421.               $chapterData['cchapter_id'] = $nCChapterID;  
  422.               $request->getSession()->set('current_explanation_cchapter_id'$nCChapterID); 
  423.               $request->getSession()->set('current_explanation_translation_id'$nExplainChapterTranslationID);               
  424.           }    
  425.       }    
  426.       
  427.       $chapterData['chapter_explanation'] = $chapterExplanations;
  428.       $chapterData['chapter_order'] = $chapterIndex;
  429.       $chapterData['book_url'] = $bookUrl;      
  430.       if(!empty($chapterExplanations))
  431.       {
  432.               $chapter_explanations_for_combo =  $this->getChapterExplanationForCombo($nCChapterID);
  433.               
  434.               $chapterData['chapter_explanations_for_combo'] = $chapter_explanations_for_combo;
  435.               
  436.               $nSelectedExplTransID $request->query->get('et');
  437.               if($nSelectedExplTransID == '')
  438.               {
  439.                   $nTransID current($chapterExplanations)['translation_id'];
  440.                   $bIsModern current($chapterExplanations)['is_modern'];
  441.               }
  442.               else
  443.               {
  444.                   foreach($chapter_explanations_for_combo as $e)
  445.                   {
  446.                       if($e['translation_id'] == $nSelectedExplTransID)
  447.                       {
  448.                           $nTransID $e['translation_id'];
  449.                           $bIsModern $e['is_modern'];
  450.                           break;
  451.                       }
  452.                   }
  453.               }
  454.                           
  455.               // Load chapter summary in text after loading the main page
  456.               if($bIsModern && !empty($nTransID) && $this->showBibleChapterSummary($language_id))
  457.               {
  458.                   $sChapterSumUrl $this->get('router')->generate('bible_chapter_summary', array(
  459.                     'translationUrl' => $translationUrl,
  460.                     'bookUrl' => $bookUrl,
  461.                     'chapterIndex' => $chapterIndex,
  462.                     'summaryTranslationID' => $nTransID
  463.                 ));    
  464.         
  465.                 $sBookName $chapterData['book']->getName();    
  466.                 $chapterData['chapter_summary_url'] = $sChapterSumUrl."?bookname=".urlencode($sBookName);
  467.               }              
  468.       }
  469.       
  470.       $bookList $this->getBibleBookList($request$chapterData['book']->getTranslation()->getId());
  471.  //     $chapterData['book_list'] = $bookList;
  472.       $nNextBookID $this->getNextBookID($chapterData['book']->getId(), $bookList);
  473.       $nPreviousBookID $this->getPreviousBookID($chapterData['book']->getId(), $bookList);
  474.       $chapterData['next_chapter'] = $this->getNextChapter($chapterData['chapter']->getId(), $nNextBookID);
  475.       $chapterData['prev_chapter'] = $this->getPreviousChapter($chapterData['chapter']->getId(), $nPreviousBookID);
  476.                       
  477.       $chapterData['bible_column_spec'] = $this->getBibleMultiColumnSpec($translationUrl$bookUrl$chapterIndex);    
  478.       $chapterData['bible_credit'] = $this->getBibleTranslationCredit($translationUrl);
  479.       
  480.           $chapterData['in_frame'] = $inFrame;
  481.           
  482.       $chapterData['slider_url'] = $this->get('router')->generate('bible_slider_chapter', array(
  483.             'translationUrl' => $translationUrl,
  484.             'bookUrl' => $bookUrl,
  485.             'chapterIndex' => $chapterIndex
  486.         ));    
  487.           
  488.       $versesView $this->createVersesView($chapterData$request);
  489.       if(!$inFrame)
  490.       {
  491.           $this->setCurrentUrl($request);           
  492.       }    
  493.        
  494.       return $versesView ;
  495.     }
  496.     /**
  497.      * $userSelected is true if the user specifically chose to view this translation, false if the translation was chosen for the user (e.g. as a site default)
  498.      */
  499.     public function verseRangeAction($translationUrl$bookUrl$chapterIndexRequest $request$verseStartIndex null$verseEndIndex null$userSelected true)
  500.     {
  501.         $msgData $this->checkBibleTranslationMsg($translationUrl); 
  502.       if(!empty($msgData))
  503.       {
  504.           $response = new Response();
  505.         $response->setStatusCode(404);
  506.           return $this->renderView('no_content'$msgData$response);
  507.       }    
  508.     
  509.         if($verseStartIndex != null && $verseStartIndex == $verseEndIndex)
  510.         {            
  511.             return $this->redirect($this->get('router')->generate('bible_verse', array(
  512.                     'translationUrl' => $translationUrl,
  513.                     'bookUrl' => $bookUrl,
  514.                     'chapterIndex' => $chapterIndex,
  515.                     'verseIndex' => $verseStartIndex
  516.                 )), 301);
  517.         }    
  518.         
  519.         $this->onloadPage($request);
  520.     
  521.         $verseRangeData $this->getChapterPath($translationUrl$bookUrl$chapterIndex$request$userSelected);
  522.         if($verseRangeData['book'] == null)
  523.         {            
  524.             $response = new Response();
  525.             $response->setStatusCode(404);
  526.             return $this->renderView('no_content', array(), $response);
  527.         }
  528.         
  529.         $verseRangeData['verses'] = ($verseRangeData['chapter'] === null) ? array() : $this->bibleData('Verse')->getByIndexRangeFromChapter(
  530.             $verseStartIndex,
  531.             $verseEndIndex,
  532.             $verseRangeData['chapter']
  533.         );
  534.         if($verseEndIndex !== null) {
  535.             $verseRangeData['verses_last_index'] = $verseEndIndex;
  536.         }
  537.         
  538.         $chapter $verseRangeData['chapter'];
  539.         if($chapter == null)
  540.         {
  541.             $verseRangeData['content_class'] = 'verse';
  542.         }
  543.         else
  544.         {                        
  545.             $chapterVerses $verseRangeData['chapter']->getVerses();            
  546.             
  547.             if($verseStartIndex != null && $verseStartIndex == $chapterVerses->first()->getOrdering() && $verseEndIndex == $chapterVerses->last()->getOrdering() )
  548.             {
  549.                 $verseRangeData['content_class'] = 'chapter';
  550.             } 
  551.             else 
  552.             {
  553.                 $verseRangeData['content_class'] = 'verse';                
  554.             }            
  555.         }
  556.         
  557.        // $verseRangeData['content_class'] = 'verse';
  558.         $verseRangeData['right_to_left'] = $this->isRightToLeft($translationUrl);
  559.         $verseRangeData['content_type'] = 'verseRange';
  560.         $verseRangeData['text_style_override'] = $this->getTextStyleOverrideForBible($verseRangeData['book']->getId());
  561.         $verseRangeData['translation_url'] = $translationUrl;
  562.                               
  563.         $verseRangeData['bible_column_spec'] = $this->getBibleMultiColumnSpec($translationUrl$bookUrl$chapterIndex$verseStartIndex$verseEndIndex);
  564.         $verseRangeData['bible_credit'] = $this->getBibleTranslationCredit($translationUrl);
  565.     
  566.         $chapterExplanations null;
  567.           $nCChapterID null;
  568.           $request->getSession()->set('current_explanation_cchapter_id''');
  569.           $CChapter $verseRangeData['chapter']->getCanonicalization();
  570.           if($CChapter != null)
  571.           {
  572.               $nCChapterID $CChapter->getId();
  573.               $chapterExplanations $this->getChapterExplanation($nCChapterID$translationUrl$request); 
  574.                         
  575.               $nExplainChapterTranslationID $this->getExplainChapterTranslation($nCChapterID$this->getCurrUserID($request), $translationUrl);        
  576.               if($nExplainChapterTranslationID > -1)
  577.               {
  578.                   $verseRangeData['cchapter_id'] = $nCChapterID;  
  579.                   $request->getSession()->set('current_explanation_cchapter_id'$nCChapterID); 
  580.                   $request->getSession()->set('current_explanation_translation_id'$nExplainChapterTranslationID);          
  581.               }    
  582.           }    
  583.           
  584.           $verseRangeData['chapter_explanation'] = $chapterExplanations;
  585.           $verseRangeData['chapter_order'] = $chapterIndex;
  586.           $verseRangeData['book_url'] = $bookUrl;      
  587.           if(!empty($chapterExplanations))
  588.           {
  589.                   $nTransID current($chapterExplanations)['translation_id'];
  590.                   $bIsModern current($chapterExplanations)['is_modern'];
  591.                   $explanation_translation $this->expositionData('Translation')->findOneById($nTransID);
  592.                   
  593.                   if($explanation_translation != null)
  594.                   {
  595.                       $passage $explanation_translation->getWork()->findFirstNonEmptyPassage($explanation_translation);
  596.                       if($passage != null)
  597.                       {    
  598.                           $verseRangeData['is_modern_chapter_summary'] = $bIsModern;
  599.                           $verseRangeData['explanation_text_style_override'] = $this->getTextStyleOverride($nTransID);
  600.                           $verseRangeData['explanation_translation'] = $explanation_translation;
  601.                           $verseRangeData['explanation_passage'] = $passage;
  602.                           $verseRangeData['explanation_authors'] = $this->getAuthorInfo($request$nTransID);
  603.                           $verseRangeData['explanation_text_to_speech'] = $this->getTextToSpeech($explanation_translation->getLanguage()->getId());
  604.                           $verseRangeData['passage_ref'] = $this->getWorkPassageRefs($passage->getId(),$nTransID$request);
  605.                           $verseRangeData['passage_multilink'] = $this->getWorkPassageMultiLink($passage->getId(),$nTransID$request);
  606.                           $verseRangeData['explanation_col1_ref'] = $this->MULTI_URL_INDICATOR_BIBLE "_" $translationUrl "_" $bookUrl "_" $chapterIndex;
  607.                           $verseRangeData['explanation_col2_ref'] = $this->MULTI_URL_INDICATOR_EXPLANATION "_" $explanation_translation->getUrl();
  608.                           
  609.                           $nExplainChapterID $this->getExplainChapterID($nTransID$this->getCurrUserID($request));        
  610.                           if(!empty($nExplainChapterID))
  611.                           {
  612.                               $verseRangeData['explanation_cchapter_id'] = $nCChapterID;  
  613.                               $verseRangeData['explanation_translation_id'] = $nTransID;                         
  614.                           }    
  615.                       }
  616.                   }    
  617.           }
  618.           
  619.         $verseRangeData['slider_url'] = $this->get('router')->generate('bible_slider_verserange', array(
  620.             'translationUrl' => $translationUrl,
  621.             'bookUrl' => $bookUrl,
  622.             'chapterIndex' => $chapterIndex,
  623.             'verseStartIndex' => $verseStartIndex,
  624.             'verseEndIndex' => $verseEndIndex
  625.         ));  
  626.         
  627.         $this->setCurrentUrl($request);         
  628.         return $this->createVersesView($verseRangeData$request);
  629.     }
  630.     /**
  631.      * Handles much of the code that is common to the full-chapter and verse-range views
  632.      */
  633.     protected function createVersesView($versesData$request)
  634.     {
  635.       //$this->logtime(' T:createVersesView enter'); $cc = 1;  
  636.                     
  637.           $this->checkIfOnMobile($request);  
  638.           $aVerseInfo $this->getVerseInfo($versesData['verses']);
  639.           
  640.           if(empty($aVerseInfo)) {
  641.             $response = new Response();
  642.             $response->setStatusCode(404);
  643.             return $this->renderView('no_content', array(), $response);
  644.         }
  645.           
  646.           $bInframe = (isset($versesData['in_frame']) && $versesData['in_frame']);          
  647.           $versesData['has_slider_item'] = $this->hasSliderItem($aVerseInfo$bInframe$request, ($versesData['content_class'] == 'chapter'));
  648.                
  649.         $aOTLE $this->getOTLERefForBible($aVerseInfo, ($versesData['content_class'] == 'chapter') ? array($versesData['chapter']) : array(), true);         
  650.      //   $versesData['otle_ref'] = $aOTLE['otle_nonmusic'];   
  651.         $versesData['otle_ref_music'] = $aOTLE['otle_music']; 
  652.         
  653.         $nCBookID $versesData['book']->getCanonicalization()->getId();
  654.         $nChapterStartOrder reset($versesData['verses'])->getChapter()->getOrdering();
  655.         $nVerseStartOrder reset($versesData['verses'])->getIndexDisplay();
  656.         $nChapterEndOrder end($versesData['verses'])->getChapter()->getOrdering();
  657.         $nVerseEndOrder end($versesData['verses'])->getIndexDisplay();
  658.     
  659.         $versesData['cbook_id'] = $nCBookID;
  660.         $versesData['chapter_start_order'] = $nChapterStartOrder;
  661.         $versesData['chapter_end_order'] = $nChapterEndOrder;
  662.         $versesData['verse_start_order'] = $nVerseStartOrder;
  663.         $versesData['verse_end_order'] = $nVerseEndOrder;
  664.                         
  665.         $bible_column_spec '';
  666.         if(array_key_exists('bible_column_spec'$versesData))
  667.             $bible_column_spec $versesData['bible_column_spec'];    
  668.             
  669.         $versesData['verses_concept'] = $this->getVerseContentWithConceptLinks($request$versesData['verses'], $bible_column_spec);
  670.         
  671.     //$this->logtime(" T:createVersesView got translations_by_language  $cc"); $cc++;
  672.        if(!array_key_exists('canonical_chapter_start'$versesData)) {
  673.             // Need to pass array($versesData['verses']) rather than just $verseData['verses'] so it will sort by ordering rather than by database ID
  674.             $canonicalRangeData DataAssembly::getVerseNumberRange(DataAssembly::canonicalize(array($versesData['verses'])));
  675.             if($canonicalRangeData !== null) {
  676.                 if(array_key_exists('chapter_index'$versesData) && $versesData['chapter_index'] != null)
  677.                 {
  678.                     $versesData['canonical_chapter_start'] = $versesData['chapter_index'];
  679.                     $versesData['canonical_chapter_end'] = null;
  680.                     $versesData['canonical_verse_start'] = null;
  681.                     $versesData['canonical_verse_end'] = null
  682.                 }
  683.                 else
  684.                 {                    
  685.                     $versesData['canonical_chapter_start'] = $canonicalRangeData['chapter_start'];
  686.                     $versesData['canonical_chapter_end'] = $canonicalRangeData['chapter_end'];
  687.                     $versesData['canonical_verse_start'] = $canonicalRangeData['verse_start'];
  688.                     $versesData['canonical_verse_end'] = $canonicalRangeData['verse_end'];           
  689.                 }
  690.             }
  691.         }
  692.         
  693.         $response null;
  694.         if($versesData['book'] === null || $versesData['chapter'] === null || empty($versesData['verses'])) {
  695.             $response = new Response();
  696.             $response->setStatusCode(404);
  697.             return $this->renderView('no_content', array(), $response);
  698.         }
  699.         $translation $versesData['book']->getTranslation();
  700.         $nTranslationID $translation->getId();
  701.         $nLanguageID $translation->getLanguage()->getId();
  702.         $versesData['hide_highlights'] = !$this->showBibleHighlights($nLanguageID);
  703. //        $versesData['lang_str_for_meta'] = $this->getLanguageStrForMeta($nLanguageID);
  704.         
  705.         $locale $request->getLocale();
  706.           $nUILanguageID $this->getLanguageIDByShortCode($locale);
  707.         $versesData['translations_by_language'] = $this->getBibleTranslationsByLanguageForVerses($nCBookID$nChapterStartOrder$nVerseStartOrder$nChapterEndOrder$nVerseEndOrder$nUILanguageID);
  708.         
  709.         $versesData['book_url'] = $versesData['book']->getUrl();
  710.         $versesData['chapter_index'] = $aVerseInfo['FirstChapterIndex'];
  711.         
  712.   //      if(!isset($versesData['book_list']) || $versesData['book_list'] == null)
  713.   //          $versesData['book_list'] = $this->getBibleBookList($nTranslationID);
  714.         
  715.         // get qBible data
  716.         $versesData['qbible_link'] = $this->getQBibleLink($versesData['book'], $versesData['chapter'], $versesData['verses']);
  717.         
  718.         // get commentary with file (pdf)
  719.         $versesData['commentary_with_doc'] = $this->getCommentaryWithDocForBible($versesData['book'], current($versesData['verses'])->getChapter()->getOrdering());
  720.         
  721.         
  722.         $versesData['text_style_override'] = $this->getTextStyleOverrideForBible($versesData['book']->getId());
  723.         $versesData['text_to_speech'] = $this->getTextToSpeech($nLanguageID);
  724.        
  725.         if($versesData['content_type'] == 'single_verse')
  726.         {    
  727.               $nSelectedExplTransID $request->query->get('et');
  728.               
  729.               $nTextLength 140;
  730.               $sVerseContent $versesData['verse']->getContent(); 
  731.               $sMetaDesc $this->fixVerseText($sVerseContent);   
  732.               $sMetaDesc $this->getTextWithinLength($sMetaDesc$nTextLength"...");          
  733.               $versesData['verse_meta_desc'] = $sMetaDesc;
  734.      
  735.             $stories DataAssembly::findVerseStories($versesData['verse'], $this->getManager(), true);
  736.             if(!empty($stories)) {
  737.                 $illustrations = array();
  738.                 $explanations = array();
  739.                 foreach($stories as $story) {
  740.                     $illustrations array_merge($illustrations$story->getIllustrations()->toArray());
  741.                     $explanations array_merge($explanations$story->getExplanations()->toArray());
  742.                 }
  743.                 $versesData['verse_illustrations'] = $illustrations;                                      
  744.                 if(count($explanations) > && $explanations[0]->selectTranslation() != null && $explanations[0]->findFirstPassage() != null)
  745.                 {               
  746.                 // get the explanation with the same language of the verse if there is
  747.                     $versesData['verse_explanations'] = $explanations;
  748.                                         
  749.                     $verseexplanation $this->getVerseExplanationInText($request$explanations$nLanguageID);
  750.                     if(!empty($verseexplanation))
  751.                     {
  752.                         $versesData['verse_explanations_for_combo'] = $this->getVerseExplanationsForVerse($versesData['verse']->getId());
  753.                     
  754.                         $versesData['verse_explanation'] = $verseexplanation;                        
  755.                         $versesData['passage_multilink'] = $this->getWorkPassageMultiLink($verseexplanation->findFirstNonEmptyPassage()->getId(),$verseexplanation->getId(), $request);
  756.                         $versesData['authors'] = $this->getAuthorInfo($request$verseexplanation->getId());
  757.                     }                     
  758.                 }    
  759.             }
  760.         }
  761.         else
  762.         {
  763.             // Full chapter
  764.             $nTextLength 150;
  765.             $sVerseText "";
  766.             foreach($versesData['verses'] as $v) {
  767.                 if($sVerseText != "")
  768.                     $sVerseText .= " ";
  769.             
  770.                 $sVerseContent $v->getContent();                  
  771.                 $sVerseText .= $this->fixVerseText($sVerseContent);
  772.                 
  773.                 if(strlen($sVerseText) > $nTextLength)
  774.                     break;          
  775.             }
  776.             
  777.             $sMetaDesc $this->getTextWithinLength($sVerseText$nTextLength"...");
  778.             $versesData['chapter_meta_desc'] = $sMetaDesc;
  779.         }
  780.         
  781.         $versesData['linktype_id'] = $this->LINK_TYPE_ID_BIBLE;    
  782.     
  783.         return $this->renderView('verses'$versesData$response);
  784.     }
  785. // TODO:  should take more args besides just key .. or body could be more generic
  786. // expands the function
  787.     
  788.     function cacheBibleTranslationDropdown$cacheKey$twigVars$dropdown_target )
  789.     {
  790.       $memcache $this->get('cache');  // really apccache, but behaves the same way
  791.     $this->logtime("  ===== "); 
  792.       if ( $memcache->contains($cacheKey) ) {
  793.           $this->logtime("  T::returning cache value for: $cacheKey"); 
  794.           $dropdown $memcache->fetch($cacheKey) . "\n<!-- from cache -->";
  795.       } else {
  796.           $this->logtime("  T::generating cache value for: $cacheKey"); 
  797.     // not found -
  798.     //$subTemplate = 'Bible:interface/translation_dropdown/dropdown.html.twig';
  799.     // full path (include bundle) to the template that is include'd
  800.     $subTemplate 'NCBSWBundle:Bible:interface/translation_dropdown/dropdown.html.twig';
  801.     $templateVariables $twigVars;
  802.     // add these because of the 'with' it gets called with
  803.     //  Bible:interface/translation_dropdown/dropdown.html.twig' with {'dropdown_target': 'index'}
  804.     //  NOT SURE --
  805.     $templateVariables'dropdown_target' ] = $dropdown_target// 'index';
  806.     // first we render the template, to get the content as html
  807.     $engine $this->container->get('templating');
  808.     $this->logtime("  T:context!  $templateVariables[dropdown_target]");
  809.     $content $engine->render($subTemplate$templateVariables);
  810.     $dropdown_html $content;
  811.     // now we cache it, so it gets used next time      
  812.     $value_to_cache "<!-- start cache $cacheKey: " strlen($dropdown_html) . " chars, at " . `date` . "-->\n"
  813.       $dropdown_html "<!-- end cached $cacheKey -->\n";
  814.     // for demonstration, keep for one minute
  815.     $memcache->save($cacheKey$value_to_cache60 ); //3600);
  816.     $dropdown $value_to_cache;
  817.       }
  818.           $this->logtime("  ===== "); 
  819.       return $dropdown;
  820.     }
  821.     /**
  822.      * $userSelected is true if the user specifically chose to view this translation, false if the translation was chosen for the user (e.g. as a site default)
  823.      */
  824.     public function verseAction($translationUrl$bookUrl$chapterIndex$verseIndexRequest $request$subverseIndex null$userSelected true)
  825.     {
  826.       $msgData $this->checkBibleTranslationMsg($translationUrl); 
  827.       if(!empty($msgData))
  828.       {
  829.           $response = new Response();
  830.         $response->setStatusCode(404);
  831.           return $this->renderView('no_content'$msgData$response);
  832.       }    
  833.       
  834.       $this->onloadPage($request);
  835.     
  836.       $cacheKey "verse:$translationUrl:$bookUrl:$chapterIndex:$verseIndex:$subverseIndex:$userSelected:" $request->getLocale();      
  837.       $this->logtime(" T:verseAction enter $cacheKey"); 
  838.       $content $this->verseAction_nonCached($translationUrl$bookUrl$chapterIndex$verseIndex$request$subverseIndex$userSelected);
  839.       $this->logtime(" T:verseAction generated content for cache entry $cacheKey");
  840.       return $content;
  841.     }
  842.     public function verseAction_nonCached($translationUrl$bookUrl$chapterIndex$verseIndexRequest $request$subverseIndex null$userSelected true)
  843.     {        
  844.         if(!is_numeric($verseIndex))
  845.         {
  846.             return $this->redirect($this->get('router')->generate('bible_chapter', array(
  847.                     'translationUrl' => $translationUrl,
  848.                     'bookUrl' => $bookUrl,
  849.                     'chapterIndex' => $chapterIndex
  850.                 )), 301);            
  851.         }    
  852.     
  853.         $verseData $this->getChapterPath($translationUrl$bookUrl$chapterIndex$request$userSelected);
  854.   //      $verseData['verse'] = $this->bibleData('Verse')->getByIndexFromChapter($verseIndex, $verseData['chapter']);
  855.   
  856.           // as verse range
  857.             $verseStartIndex $verseIndex;
  858.             $verseEndIndex $verseIndex;
  859.       
  860.             $verseData['verses'] = ($verseData['chapter'] === null) ? array() : $this->bibleData('Verse')->getByIndexRangeFromChapter(
  861.                 $verseStartIndex,
  862.                 $verseEndIndex,
  863.                 $verseData['chapter']
  864.             ); 
  865.            
  866.         if(empty($verseData['verses']))
  867.         {
  868.             return $this->redirect($this->get('router')->generate('bible_chapter', array(
  869.                     'translationUrl' => $translationUrl,
  870.                     'bookUrl' => $bookUrl,
  871.                     'chapterIndex' => $chapterIndex
  872.                 )), 301);            
  873.         }
  874.         
  875.         $verseData['verse'] = current($verseData['verses']);
  876.       
  877.         $verseData['translation_url'] = $translationUrl;
  878.         
  879.         // Don't show subverse view. Always show the main verse view 
  880.   /*      if($subverseIndex !== null) {
  881.             $verseData['subverse'] = ($verseData['verse'] === null) ? null : $this->bibleData('Verse')->getSubverseByIndexFromVerse($subverseIndex, $verseData['verse']);
  882.             
  883.             if($verseData['verse'] !== null) {
  884.                 $canonicalRangeData = DataAssembly::getVerseNumberRange($verseData['verse']->getCanonicalization()->toArray());
  885.                 if($canonicalRangeData !== null) {
  886.                     $verseData['canonical_chapter_start'] = $canonicalRangeData['chapter_start'];
  887.                     $verseData['canonical_chapter_end'] = $canonicalRangeData['chapter_end'];
  888.                     $verseData['canonical_verse_start'] = $canonicalRangeData['verse_start'];
  889.                     $verseData['canonical_verse_end'] = $canonicalRangeData['verse_end'];
  890.                 }
  891.             }
  892.             $verseData['right_to_left'] = $this->isRightToLeft($translationUrl);
  893.             $verseData['bible_column_spec'] = $this->getBibleMultiColumnSpec($translationUrl, $bookUrl, $chapterIndex, $subverseIndex);
  894.             $verseData['bible_credit'] = $this->getBibleTranslationCredit($translationUrl);
  895.             $sSubVerseIndexDisplay = $verseData['subverse']->getIndexDisplay();
  896.             $nVerseID = null;
  897.             if(strpos($sSubVerseIndexDisplay, '-') !== false)
  898.                 $nVerseID = $verseData['verse']->getId();
  899.             else
  900.                 $nVerseID = $verseData['subverse']->getId();    
  901.             
  902.             if($nVerseId != null && $nVerseId != '')
  903.             {    
  904.                 $verseData['next_verse'] = $this->getNextVerse($nVerseID);
  905.                   $verseData['prev_verse'] = $this->getPreviousVerse($nVerseID);
  906.               }
  907.               
  908.             return $this->createVerseView($verseData, $request);
  909.         }
  910.         else
  911.         { */       
  912.                         
  913.             if($verseEndIndex !== null) {
  914.                 $verseData['verses_last_index'] = $verseEndIndex;
  915.             }
  916.              
  917.             $nVerseID $verseData['verse']->getId();  
  918.             $verseData['content_class'] = 'verse';
  919.             $verseData['content_type'] = 'single_verse';
  920.         //    $verseData['verse'] = $this->bibleData('Verse')->getByIndexFromChapter($verseIndex, $verseData['chapter']);
  921.             $verseData['right_to_left'] = $this->isRightToLeft($translationUrl);
  922.             $verseData['translation_url'] = $translationUrl;
  923.                                       
  924.           $verseData['bible_column_spec'] = $this->getBibleMultiColumnSpec($translationUrl$bookUrl$chapterIndex$verseIndex);
  925.                $verseData['bible_credit'] = $this->getBibleTranslationCredit($translationUrl);
  926.               $verseData['next_verse'] = $this->getNextVerse($nVerseID);
  927.               $verseData['prev_verse'] = $this->getPreviousVerse($nVerseID);              
  928.               $verseData['book_url'] = $bookUrl;
  929.               $verseData['chapter_index'] = $chapterIndex;
  930.               $verseData['verse_index'] = $verseIndex;
  931.               $verseData['verse_id_for_verse_of_day'] = $nVerseID;
  932.               
  933.               // show chapter summary on verse level
  934.               $cchapter $verseData['chapter']->getCanonicalization();
  935.               if($cchapter != null)
  936.               {
  937.                   $nCChapterID $cchapter->getId();
  938.                   $chapterExplanations $this->getChapterExplanation($nCChapterID$translationUrl$request);
  939.                 $verseData['chapter_explanation'] = $chapterExplanations;
  940.                 $verseData['chapter_order'] = $chapterIndex;
  941.                 if(!empty($chapterExplanations))
  942.                 {
  943.                       $nTransID current($chapterExplanations)['translation_id'];
  944.                       $explanation_translation $this->expositionData('Translation')->findOneById($nTransID);
  945.                       
  946.                       if($explanation_translation != null)
  947.                       {
  948.                           $passage $explanation_translation->getWork()->findFirstNonEmptyPassage($explanation_translation);
  949.                           if($passage != null)
  950.                           {
  951.                               $verseData['explanation_text_style_override'] = $this->getTextStyleOverride($nTransID);
  952.                               $verseData['explanation_translation'] = $explanation_translation;
  953.                               $verseData['explanation_passage'] = $passage;
  954.                               $verseData['explanation_authors'] = $this->getAuthorInfo($request$nTransID);
  955.                               $verseData['explanation_text_to_speech'] = $this->getTextToSpeech($explanation_translation->getLanguage()->getId());
  956.                               $verseData['passage_ref'] = $this->getWorkPassageRefs($passage->getId(),$nTransID$request);
  957.                               $verseData['passage_multilink'] = $this->getWorkPassageMultiLink($passage->getId(),$nTransID$request);
  958.                               $verseData['explanation_col1_ref'] = $this->MULTI_URL_INDICATOR_BIBLE "_" $translationUrl "_" $bookUrl "_" $chapterIndex;
  959.                               $verseData['explanation_col2_ref'] = $this->MULTI_URL_INDICATOR_EXPLANATION "_" $explanation_translation->getUrl();
  960.                               
  961.                               $nExplainChapterID $this->getExplainChapterID($nTransID$this->getCurrUserID($request));        
  962.                               if(!empty($nExplainChapterID))
  963.                               {
  964.                                   $verseData['explanation_cchapter_id'] = $nCChapterID;  
  965.                                   $verseData['explanation_translation_id'] = $nTransID;                         
  966.                               }    
  967.                           }
  968.                       }    
  969.                   }    
  970.             }            
  971.             
  972.             $verseData['slider_url'] = $this->get('router')->generate('bible_slider_verse', array(
  973.                 'translationUrl' => $translationUrl,
  974.                 'bookUrl' => $bookUrl,
  975.                 'chapterIndex' => $chapterIndex,
  976.                 'verseStartIndex' => $verseIndex
  977.             ));
  978.             
  979.             $versesView $this->createVersesView($verseData$request);
  980.             $this->setCurrentUrl($request);             
  981.             return $versesView;
  982.      //   }        
  983.     }
  984.        
  985.     // Creates multi-chapter view for access via both canonical and translation-specific numbering
  986.     public function createVerseView($verseData$request)
  987.     {        
  988.         $this->checkIfOnMobile($request);
  989.         $stories DataAssembly::findVerseStories($verseData['verse'], $this->getManager(), true);
  990.         $aVerse = array();
  991.         if(!array_key_exists('subverse'$verseData))
  992.             $aVerse = array($verseData['verse']);
  993.         else
  994.         {
  995.             $aVerse = array(
  996.                 $verseData['verse'],
  997.                 $verseData['subverse']
  998.             );
  999.         }
  1000.         
  1001.         $aVerseInfo $this->getVerseInfo($aVerse); 
  1002.         
  1003.         $bInframe = (isset($verseData['in_frame']) && $verseData['in_frame']);
  1004.         $verseData['has_slider_item'] = $this->hasSliderItem($aVerseInfo$bInframe$request);       
  1005.                         
  1006.         if(!empty($stories)) {
  1007.             $illustrations = array();
  1008.             $explanations = array();
  1009.             foreach($stories as $story) {
  1010.                 $illustrations array_merge($illustrations$story->getIllustrations()->toArray());
  1011.                 $explanations array_merge($explanations$story->getExplanations()->toArray());
  1012.             }
  1013.             $verseData['verse_illustrations'] = $illustrations;
  1014.                             
  1015.             if(count($explanations) > && $explanations[0]->selectTranslation() != null && $explanations[0]->findFirstPassage() != null)
  1016.             {                          
  1017.                 $verseData['verse_explanations'] = $explanations
  1018.                 
  1019.                 $verseexplanation $this->getVerseExplanationInText($request$explanations$nLanguageID);
  1020.                 if(!empty($verseexplanation))
  1021.                 {                                            
  1022.                     $versesData['verse_explanation'] = $verseexplanation;                        
  1023.                     $versesData['passage_multilink'] = $this->getWorkPassageMultiLink($verseexplanation->findFirstNonEmptyPassage()->getId(),$verseexplanation->getId(), $request);
  1024.                     $versesData['authors'] = $this->getAuthorInfo($request$verseexplanation->getId());
  1025.                 }
  1026.             }        
  1027.         }
  1028.         $verseData['translations_by_language'] = $this->getBibleTranslationsByLanguage($verseData['book']->getCanonicalization()->getId());
  1029.         $verseData['verses_concept'] = $this->getVerseContentWithConceptLinks($request$verseData['verse'], $verseData['bible_column_spec']);
  1030.         
  1031.         $verseData['text_style_override'] = $this->getTextStyleOverrideForBible($verseData['book']->getId());
  1032.         $response null;
  1033.         if($verseData['verse'] === null) {
  1034.             $response = new Response();
  1035.             $response->setStatusCode(404);
  1036.         }
  1037.         
  1038. //        $verseData['book_list'] = $this->getBibleBookList($verseData['book']->getTranslation()->getId());
  1039.     
  1040.         return $this->renderView('verse'$verseData$response);
  1041.     }
  1042.     public function canonicalNumberedContentAction($translationUrl$bookUrl$chapterStartIndexRequest $request$chapterEndIndex null$verseStartIndex null$verseEndIndex null)
  1043.     {
  1044.         $msgData $this->checkBibleTranslationMsg($translationUrl); 
  1045.           if(!empty($msgData))
  1046.           {
  1047.               $response = new Response();
  1048.             $response->setStatusCode(404);
  1049.               return $this->renderView('no_content'$msgData$response);
  1050.           }    
  1051.     
  1052.         $translation $this->bibleData('Translation')->findOneBy(array('url' => TextFormatter::urlify($translationUrl), 'enabled' => true));
  1053.         $canonicalBook $this->bibleData('Canonical\Book')->findOneByUrl(TextFormatter::urlify($bookUrl));
  1054.         if($canonicalBook == null)
  1055.         {
  1056.             $response = new Response();
  1057.             $response->setStatusCode(404);
  1058.               return $this->renderView('no_content', array(), $response);
  1059.         }        
  1060.         
  1061.         if($chapterStartIndex != null)        
  1062.         {            
  1063.             $book $this->getBookByUrl($translationUrl$bookUrl$requestfalse);            
  1064.                         
  1065.             if($book != null)
  1066.             {
  1067.                 $lastChapterNum $book->getChapters()->last()->getOrdering();   
  1068.                 if($lastChapterNum $chapterStartIndex)
  1069.                 {                
  1070.                     $chapterStartIndex $lastChapterNum;
  1071.                     $verseStartIndex null;
  1072.                     $verseEndIndex null;   
  1073.                 }    
  1074.                     
  1075.                 if($chapterEndIndex != null && $lastChapterNum $chapterEndIndex
  1076.                 {               
  1077.                     $chapterEndIndex $lastChapterNum;          
  1078.                     $verseStartIndex null;
  1079.                     $verseEndIndex null;
  1080.                 }                                                        
  1081.             } 
  1082.             else
  1083.             {
  1084.                 $response = new Response();
  1085.                 $response->setStatusCode(404);
  1086.                   return $this->renderView('no_content', array(), $response);
  1087.             }                                         
  1088.             
  1089.             $chapter $this->bibleData('Chapter')->findOneBy(array('book' => $book->getId(), 'ordering' => $chapterStartIndex));
  1090.             
  1091.             if($chapter != null)
  1092.             {     
  1093.                 if($verseStartIndex != null)
  1094.                 {  
  1095.                     $verses $chapter->getVerses();
  1096.                     $nOrder 0;
  1097.                     foreach($verses as $verse) {                
  1098.                         $sIndexDisplay $verse->getIndexDisplay();
  1099.                         if(is_numeric ($sIndexDisplay))
  1100.                         {
  1101.                             $nTempOrder = (int)$sIndexDisplay;
  1102.                             if($nTempOrder $verseStartIndex)
  1103.                                 break;
  1104.                             else
  1105.                                 $nOrder $nTempOrder;    
  1106.                         }    
  1107.                     }
  1108.                     
  1109.                     if($nOrder != $verseStartIndex)
  1110.                     {
  1111.                         //$verseStartIndex = $nOrder;       
  1112.                         $verseStartIndex null;    // go to chapter level   
  1113.                         $verseEndIndex null;              
  1114.                     }                        
  1115.                 }
  1116.                 
  1117.                 if($verseEndIndex != null)
  1118.                 {  
  1119.                     $verses $chapter->getVerses();
  1120.                     $nOrder 0;
  1121.                     foreach($verses as $verse) {                
  1122.                         $sIndexDisplay $verse->getIndexDisplay();
  1123.                         if(is_numeric ($sIndexDisplay))
  1124.                         {
  1125.                             $nTempOrder = (int)$sIndexDisplay;
  1126.                             if($nTempOrder $verseEndIndex)
  1127.                                 break;
  1128.                             else
  1129.                                 $nOrder $nTempOrder;    
  1130.                         }    
  1131.                     }
  1132.                     
  1133.                     if($nOrder != $verseEndIndex)
  1134.                     {
  1135.                         //$verseEndIndex = $nOrder;       
  1136.                         $verseStartIndex null;    // go to chapter level   
  1137.                         $verseEndIndex null;                          
  1138.                     }    
  1139.                 }                                            
  1140.             }                             
  1141.         } 
  1142.         $canonicalVerseData DataAssembly::getVerseRangeFromBook($canonicalBook$chapterStartIndex$chapterEndIndex$verseStartIndex$verseEndIndex);
  1143.                 
  1144.         $translatedVerseData DataAssembly::decanonicalizeSpan($this->getManager(), $translation->getId(), $canonicalVerseData);
  1145.           
  1146.         $contentData = array(
  1147.             'canonical_chapter_start' => $chapterStartIndex,
  1148.             'canonical_chapter_end' => $chapterEndIndex,
  1149.             'canonical_verse_start' => $verseStartIndex,
  1150.             'canonical_verse_end' => $verseEndIndex
  1151.         );
  1152.         
  1153.         $contentData['bible_column_spec'] = $this->getMultiColumnSpecForChapterRange($translationUrl$bookUrl$chapterStartIndex$chapterEndIndex$verseStartIndex$verseEndIndex);
  1154.         if(count($translatedVerseData) === 1) {
  1155.             // Single chapter
  1156.             $verseList reset($translatedVerseData);
  1157.             $v1 reset($verseList)->findMainVerse();
  1158.             $vn end($verseList)->findMainVerse();
  1159.             $contentData['chapter'] = $v1->getChapter();
  1160.             $contentData['book'] = $contentData['chapter']->getBook();
  1161.             if(count($verseList) === 1) {
  1162.                 $listedVerse reset($verseList);
  1163.         //        return $this->redirect($this->getUriDiscovery()->discoverUri($listedVerse), 301);
  1164.         
  1165.                 $redirectUrl $this->get('router')->generate('bible_verse', array(
  1166.                     'translationUrl' => $contentData['book']->getTranslation()->getUrl(),
  1167.                     'bookUrl' => $contentData['book']->getUrl(),
  1168.                     'chapterIndex' => $contentData['chapter']->getOrdering(),
  1169.                     'verseIndex' => $listedVerse->getIndexDisplay()
  1170.                 ));
  1171.                 
  1172.                 return $this->redirect($redirectUrl301); 
  1173.         
  1174.                 /* To build this page immediately rather than redirecting:
  1175.                 if($listedVerse->getVerse() === null) {
  1176.                     $contentData['verse'] = $listedVerse;
  1177.                 } else {
  1178.                     $contentData['subverse'] = $listedVerse;
  1179.                     $contentData['verse'] = $listedVerse->getVerse();
  1180.                 }
  1181.                 return $this->createVerseView($contentData, $request);
  1182.                 */
  1183.             }
  1184.             $contentData['verses'] = $verseList;
  1185.             // Check whether we're showing an entire chapter or just part of a chapter
  1186.             $chapterVerses $contentData['chapter']->getVerses();
  1187.             if( $v1->getId() == $chapterVerses->first()->getId() && $vn->getId() == $chapterVerses->last()->getId() ) {
  1188.                // return $this->redirect($this->getUriDiscovery()->discoverUri($contentData['chapter']), 301);
  1189.                return $this->redirect($this->get('router')->generate('bible_chapter', array(
  1190.                     'translationUrl' => $translationUrl,
  1191.                     'bookUrl' => $contentData['book']->getUrl(),
  1192.                     'chapterIndex' => $contentData['chapter']->getOrdering()
  1193.                 )), 301);
  1194.                
  1195.             } else {
  1196.                 return $this->redirect($this->get('router')->generate('bible_verse_range', array(
  1197.                     'translationUrl' => $translationUrl,
  1198.                     'bookUrl' => $contentData['book']->getUrl(),
  1199.                     'chapterIndex' => $contentData['chapter']->getOrdering(),
  1200.                     'verseStartIndex' => $v1->getIndexDisplay(),
  1201.                     'verseEndIndex' => $vn->getIndexDisplay()
  1202.                 )), 301);
  1203.             }
  1204.             /* To build this page immediately rather than redirecting:
  1205.             if( $v1->getId() == $chapterVerses->first()->getId() && $vn->getId() == $chapterVerses->last()->getId() ) {
  1206.                 $contentData['content_class'] = 'chapter';
  1207.             } else {
  1208.                 $contentData['content_class'] = 'verses';
  1209.                 $contentData['verses_last_index'] = $vn->getIndexDisplay();
  1210.             }
  1211.             return $this->createVersesView($contentData, $request);
  1212.             */
  1213.         } elseif(count($translatedVerseData) === 0) {
  1214.             // Zero chapters -- this translation doesn't have this book/chapter(s)/verse(s)       
  1215.             $response = new Response();
  1216.             $response->setStatusCode(404);
  1217.               return $this->renderView('no_content', array(), $response);
  1218.         } else {
  1219.             // Multiple chapters
  1220.             $firstChapterContent reset($translatedVerseData);
  1221.             $v1 reset($firstChapterContent)->findMainVerse();
  1222.             $lastChapterContent end($translatedVerseData);
  1223.             $vn end($lastChapterContent)->findMainVerse();
  1224.             $c1 $v1->getChapter();
  1225.             $cn $vn->getChapter();
  1226.             $contentData['contents'] = $translatedVerseData;
  1227.             $contentData['book'] = $c1->getBook();
  1228.             if( $v1->getId() == $c1->getVerses()->first()->getId() && $vn->getId() == $cn->getVerses()->last()->getId() ) {
  1229.                 return $this->redirect($this->get('router')->generate('bible_chapter_range', array(
  1230.                     'translationUrl' => $translationUrl,
  1231.                     'bookUrl' => $contentData['book']->getUrl(),
  1232.                     'chapterStartIndex' => $c1->getOrdering(),
  1233.                     'chapterEndIndex' => $cn->getOrdering()
  1234.                 )), 301);
  1235.             } else {
  1236.                 return $this->redirect($this->get('router')->generate('bible_chapter_verse_range', array(
  1237.                     'translationUrl' => $translationUrl,
  1238.                     'bookUrl' => $contentData['book']->getUrl(),
  1239.                     'chapterStartIndex' => $c1->getOrdering(),
  1240.                     'chapterEndIndex' => $cn->getOrdering(),
  1241.                     'verseStartIndex' => $v1->getIndexDisplay(),
  1242.                     'verseEndIndex' => $vn->getIndexDisplay()
  1243.                 )), 301);
  1244.             }
  1245.             /* To build this page immediately rather than redirecting:
  1246.             if( $v1->getId() == $c1->getVerses()->first()->getId() && $vn->getId() == $cn->getVerses()->last()->getId() ) {
  1247.                 $contentData['content_class'] = 'chapter';
  1248.                 $contentData['range_name'] = $contentData['book']->getName().' '.$c1->getOrdering().'-'.$cn->getOrdering();
  1249.             } else {
  1250.                 $contentData['content_class'] = 'verse';
  1251.                 $contentData['range_name'] = $contentData['book']->getName().' '.$c1->getOrdering().':'.$v1->getIndexDisplay().' - '.$cn->getOrdering().':'.$vn->getIndexDisplay();
  1252.             }
  1253.             return $this->createChaptersView($contentData);
  1254.             */
  1255.         }
  1256.     }
  1257.     public function storyTextAction($storyUrlRequest $request$bibleTranslationUrl null)
  1258.     {
  1259.         $locale $request->getLocale();
  1260.         if($bibleTranslationUrl === null) {
  1261.             // For SEO purposes, we'll send the visitor to the route for the story with the default translation
  1262.             $defaultLanguage $this->getRepository('Language')->findOneBySiteDefault(true);
  1263.             $defaultTranslation $this->bibleData('Translation')->findOneBy(array('language' => $defaultLanguage->getId(), 'languageDefault' => true'enabled' => true));
  1264.             return $this->redirect($this->get('router')->generate('bible_translated_story_text', array(
  1265.                 'storyUrl' => $storyUrl,
  1266.                 'bibleTranslationUrl' => $defaultTranslation->getUrl()
  1267.             )), 301);
  1268.         }
  1269.         $story $this->bibleData('Stories\Story')->findOneBy(array('url' => $storyUrl'level_id' => $this->STORY_LEVEL_ID_BIBLE'isPublic' => true));
  1270.         
  1271.         $response null;
  1272.         if($story == null) {
  1273.             $response = new Response();
  1274.             $response->setStatusCode(404);
  1275.             return $this->renderView('no_content', array(), $response);
  1276.         }    
  1277.                      
  1278.         $translation $this->bibleData('Translation')->findOneBy(array('url' => $bibleTranslationUrl'enabled' => true));
  1279.         
  1280.         $response null;
  1281.         if($translation === null) {
  1282.             $response = new Response();
  1283.             $response->setStatusCode(404);
  1284.             return $this->renderView('no_content', array(), $response);
  1285.         }   
  1286.         
  1287.         if($locale != 'en')
  1288.         {
  1289.             $sStoryName $this->getBibleStoryName($story->getId(), $locale); 
  1290.             if(!empty($sStoryName))
  1291.                 $story->setName($sStoryName);
  1292.         }  
  1293.         
  1294.         $aPublicStoryExplanation $this->getExplainedStoryList($locale$story->getId());
  1295.         $bHasPublicStoryExplanation = !empty($aPublicStoryExplanation);
  1296.         
  1297.         $right_to_left $translation->getLanguage()->getRightToLeft();
  1298.         
  1299.         $canonicalStartVerse $story->getStartVerse();
  1300.         $canonicalEndVerse $story->getEndVerse();
  1301.         $canonicalStartChapter $canonicalStartVerse->getChapter();
  1302.         $canonicalEndChapter $canonicalEndVerse->getChapter();
  1303.         $canonicalBook $canonicalStartChapter->getBook();
  1304.         $contentsCanonical DataAssembly::getVerseRangeFromBook($canonicalBook$canonicalStartChapter->getOrdering(), $canonicalEndChapter->getOrdering(), $canonicalStartVerse->getOrdering(), $canonicalEndVerse->getOrdering());
  1305.         $contents DataAssembly::decanonicalizeSpan($this->getManager(), $translation->getId(), $contentsCanonical);
  1306.         $this->onloadPage($request);
  1307.         if(count($contents) === 0) {
  1308.             // Content does not exist in this translation
  1309.             $response = new Response();
  1310.             $response->setStatusCode(404);
  1311.             return $this->renderView('no_content', array(), $response);
  1312.         } else {
  1313.             $this->setCurrentUrl($request);             
  1314.             $firstChapterContents reset($contents);
  1315.             $firstVerse reset($firstChapterContents);
  1316.             $firstChapter $firstVerse->findMainVerse()->getChapter();
  1317.             $lastChapterContents end($contents);
  1318.             $lastVerse end($lastChapterContents);
  1319.             $lastChapter $lastVerse->findMainVerse()->getChapter();
  1320.             $completeChapters $firstVerse === $firstChapter->getVerses()->first() && $lastVerse === $lastChapter->getVerses()->last();
  1321.             $storyData = array(
  1322.                 'story' => $story,
  1323.                 'has_public_explanation' => $bHasPublicStoryExplanation,
  1324.                 'translation' => $translation,
  1325.                 'book' => $firstVerse->findMainVerse()->getChapter()->getBook(),
  1326.                 'content_class' => 'storytext',
  1327.                 'right_to_left' => $right_to_left
  1328.             );
  1329.             
  1330.      //       $storyData['next_chapter'] = $this->getNextChapter($firstChapter->getId());
  1331.      //         $storyData['prev_chapter'] = $this->getPreviousChapter($firstChapter->getId());
  1332.      
  1333.              $storyData['translation_url'] = $translation->getUrl();
  1334.              $storyData['book_url'] = $canonicalBook->getUrl();
  1335.              
  1336.              $storyData['bible_column_spec'] = $this->getBibleMultiColumnSpec($storyData['translation_url'], $storyData['book_url'], $canonicalStartChapter->getOrdering(), $canonicalStartVerse->getOrdering(), $canonicalEndVerse->getOrdering());    
  1337.             
  1338.             if(count($contents) === 1) {
  1339.                 // Story is entirely within a single chapter
  1340.                 $storyData['chapter'] = $firstChapter;
  1341.                 $storyData['verses'] = $firstChapterContents;
  1342.                 if(!$completeChapters) {
  1343.                     $storyData['verses_last_index'] = $lastVerse->getFullIndexDisplay();
  1344.                 }
  1345.                 $storyData['content_type'] = 'verseRange';
  1346.                 
  1347.                 $storyData['slider_url'] = $this->get('router')->generate('bible_slider_verserange', array(
  1348.                         'translationUrl' => $storyData['translation_url'],
  1349.                         'bookUrl' => $storyData['book_url'],
  1350.                         'chapterIndex' => $firstChapter->getOrdering(),
  1351.                         'verseStartIndex' => $canonicalStartVerse->getOrdering(),
  1352.                         'verseEndIndex' => $canonicalEndVerse->getOrdering()
  1353.                     ));
  1354.                     
  1355.                 return $this->createVersesView($storyData$request);
  1356.             } else {
  1357.                 // Story contains text from more than one chapter
  1358.                 $storyData['contents'] = $contents;
  1359.                 if($completeChapters) {
  1360.                     $storyData['range_name'] = $this->get('translator')->trans("bible.chapternav.bookchapterrange", array(
  1361.                         '%bookname%' => $storyData['book']->getName(),
  1362.                         '%chapterstart%' => $firstChapter->getOrdering(),
  1363.                         '%chapterend%' => $lastChapter->getOrdering()
  1364.                     )); 
  1365.                     
  1366.                     $storyData['slider_url'] = $this->get('router')->generate('bible_slider_chapter_range', array(
  1367.                         'translationUrl' => $storyData['translation_url'],
  1368.                         'bookUrl' => $storyData['book_url'],
  1369.                         'chapterStartIndex' => $firstChapter->getOrdering(),
  1370.                         'chapterEndIndex' => $lastChapter->getOrdering()
  1371.                     ));
  1372.                 } else {
  1373.                     $storyData['range_name'] = $this->get('translator')->trans("bible.chapternav.bookchapterrangeverserange", array(
  1374.                         '%bookname%' => $storyData['book']->getName(),
  1375.                         '%chapterstart%' => $firstChapter->getOrdering(),
  1376.                         '%chapterend%' => $lastChapter->getOrdering(),
  1377.                         '%versestart%' => $firstVerse->getFullIndexDisplay(),
  1378.                         '%verseend%' => $lastVerse->getFullIndexDisplay()
  1379.                     )); 
  1380.                     
  1381.                     $storyData['slider_url'] = $this->get('router')->generate('bible_slider_chapter_verse_range', array(
  1382.                         'translationUrl' => $storyData['translation_url'],
  1383.                         'bookUrl' => $storyData['book_url'],
  1384.                         'chapterStartIndex' => $firstChapter->getOrdering(),
  1385.                         'chapterEndIndex' => $lastChapter->getOrdering(),
  1386.                         'verseStartIndex' => $canonicalStartVerse->getOrdering(),
  1387.                         'verseEndIndex' => $canonicalEndVerse->getOrdering()
  1388.                     ));
  1389.                 }
  1390.               //  echo $storyData['slider_url'];
  1391.                 return $this->createChaptersView($storyData$request);
  1392.             }
  1393.         }
  1394.     }
  1395.     public function compareVersesAction($translationUrl1$translationUrl2$bookUrl$chapterStartIndexRequest $request$chapterEndIndex null$verseStartIndex null$verseEndIndex null)
  1396.     {
  1397.         $this->checkIfOnMobile($request);
  1398.         $msgData $this->checkBibleTranslationMsg($translationUrl1); 
  1399.         if(empty($msgData))
  1400.             $msgData $this->checkBibleTranslationMsg($translationUrl2);
  1401.       if(!empty($msgData))
  1402.       {
  1403.           $response = new Response();
  1404.         $response->setStatusCode(404);
  1405.           return $this->renderView('no_content'$msgData$response);
  1406.       }    
  1407.         $this->onloadPage($request);
  1408.         
  1409.         $response null;
  1410.         $translation1 $this->getBibleTranslationInfo($translationUrl1$bookUrl);
  1411.         $translation2 $this->getBibleTranslationInfo($translationUrl2$bookUrl);
  1412.         
  1413.         if(empty($translation1) || empty($translation2))
  1414.         {
  1415.             $response = new Response();
  1416.             $response->setStatusCode(404);
  1417.             return $this->renderView('no_content_back', array(), $response);
  1418.         } 
  1419.         
  1420.         $right_to_left1 $translation1['righttoleft'];
  1421.         $right_to_left2 $translation2['righttoleft'];
  1422.         $canonicalBook $this->bibleData('Canonical\Book')->findOneByUrl($bookUrl);
  1423.        
  1424.         if($chapterStartIndex != null)
  1425.         {
  1426.             $lastChapterNumBook1 $translation1['last_chapter_order'];
  1427.             if($lastChapterNumBook1 $chapterStartIndex)
  1428.             {
  1429.                 $response = new Response();
  1430.                 $response->setStatusCode(404);
  1431.                 return $this->renderView('no_chapter_back', array(), $response);
  1432.             }
  1433.         
  1434.             $lastChapterNumBook2 $translation2['last_chapter_order'];
  1435.             if($lastChapterNumBook2 $chapterStartIndex)
  1436.             {
  1437.                 $response = new Response();
  1438.                 $response->setStatusCode(404);
  1439.                 return $this->renderView('no_chapter_back', array(), $response);
  1440.             }
  1441.         }
  1442.                 
  1443.         $bVerseLevel false;
  1444.         
  1445.         $bible_column_spec $this->getMultiColumnSpecForChapterRange($translationUrl1$bookUrl$chapterStartIndex$chapterEndIndex$verseStartIndex$verseEndIndex);
  1446.         $canonicalVerseData DataAssembly::getVerseRangeFromBook($canonicalBook$chapterStartIndex$chapterEndIndex$verseStartIndex$verseEndIndex);
  1447.         $verses1 DataAssembly::decanonicalizeSpan($this->getManager(), $translation1['id'], $canonicalVerseData);
  1448.         
  1449.         if(count($verses1) < 1)
  1450.         {
  1451.             $response = new Response();
  1452.             $response->setStatusCode(404);
  1453.             return $this->renderView('no_chapter_back', array(), $response);
  1454.         }
  1455.                 
  1456.         $verses2 DataAssembly::decanonicalizeSpan($this->getManager(), $translation2['id'], $canonicalVerseData);              
  1457.       
  1458.         $aVerse array_reduce($verses1'array_merge', array());
  1459.         $aVerse2 array_reduce($verses2'array_merge', array());
  1460.       
  1461.         $nCBookID $canonicalBook->getId();        
  1462.         $nChapterStartOrder reset($aVerse)->getChapter()->getOrdering();
  1463.         $nVerseStartOrder reset($aVerse)->getIndexDisplay();
  1464.         $nChapterID reset($aVerse)->getChapter()->getId();
  1465.         $nChapterEndOrder end($aVerse)->getChapter()->getOrdering();
  1466.         $nVerseEndOrder end($aVerse)->getIndexDisplay();
  1467.         
  1468.         $locale $request->getLocale();
  1469.           $nUILanguageID $this->getLanguageIDByShortCode($locale);
  1470.       
  1471.         $templateData = array(
  1472.             'translation1' => $translation1,            
  1473.             'contents1' => $verses1,
  1474.             'translation2' => $translation2,            
  1475.             'contents2' => $verses2,
  1476.             'translations_by_language' => $this->getBibleTranslationsByLanguageForVerses($nCBookID$nChapterStartOrder$nVerseStartOrder$nChapterEndOrder$nVerseEndOrder$nUILanguageID),  
  1477.             'verses_concept1' => $this->getVerseContentWithConceptLinks($request$aVerse$bible_column_spec),  
  1478.             'verses_concept2' => $this->getVerseContentWithConceptLinks($request$aVerse2$bible_column_spec2),     
  1479.             'canonical_book' => $canonicalBook,
  1480.             'contents_canonical' => $canonicalVerseData,
  1481.             'canonical_chapter_start' => $chapterStartIndex,
  1482.             'canonical_chapter_end' => $chapterEndIndex,
  1483.             'canonical_verse_start' => $verseStartIndex,
  1484.             'canonical_verse_end' => $verseEndIndex,
  1485.             'right_to_left1' => $right_to_left1,
  1486.             'right_to_left2' => $right_to_left2,
  1487.             'text_style_override1' => $this->getTextStyleOverrideForBible($translation1['book_id']),
  1488.             'text_style_override2' => $this->getTextStyleOverrideForBible($translation2['book_id']),
  1489.             'text_to_speech1' => $this->getTextToSpeech($translation1['language_id']),
  1490.             'text_to_speech2' => $this->getTextToSpeech($translation2['language_id'])
  1491.         );
  1492.         
  1493.         $templateData['cbook_id'] = $nCBookID;
  1494.         $templateData['chapter_start_order'] = $nChapterStartOrder;
  1495.         $templateData['chapter_end_order'] = $nChapterEndOrder;
  1496.         $templateData['verse_start_order'] = $nVerseStartOrder;
  1497.         $templateData['verse_end_order'] = $nVerseEndOrder;
  1498.         
  1499.         if($verseStartIndex == null && $chapterEndIndex == null)
  1500.             $templateData['content_class'] = "chapter";
  1501.         
  1502.         $templateData['bible_column_spec1'] = $this->getMultiColumnSpecForChapterRange($translationUrl1$bookUrl$chapterStartIndex$chapterEndIndex$verseStartIndex$verseEndIndex);
  1503.         $templateData['bible_column_spec2'] = $this->getMultiColumnSpecForChapterRange($translationUrl2$bookUrl$chapterStartIndex$chapterEndIndex$verseStartIndex$verseEndIndex);
  1504.         $bEmptyContent2 = empty($templateData['contents2']);
  1505.         
  1506.         if($bEmptyContent2)
  1507.         {
  1508.             $response = new Response();
  1509.             $response->setStatusCode(404);
  1510.             return $this->renderView('no_content_back', array(), $response);
  1511.         } 
  1512.         else
  1513.         {
  1514.             $aVerseInfo $this->getVerseInfo($aVerse);
  1515.             $aVerseInfo2 $this->getVerseInfo($aVerse2);
  1516.          //   $templateData['verse_story'] = $this->getStoriesForVerses($aVerseInfo, $request);
  1517.                 
  1518.             // If we have a single (canonical) verse, we'll check if it has an explanation; otherwise, we'll look for verses that have explanations            
  1519.             if($chapterEndIndex === null && $verseStartIndex !== null && ($verseEndIndex === null || $verseEndIndex <= $verseStartIndex)) {
  1520.                 $bVerseLevel true;
  1521.                 $chapterList reset($canonicalVerseData);
  1522.                 $verse reset($chapterList);
  1523.                 $verseId $verse->getId();                
  1524.                 $verseStory $this->bibleData('Stories\Story')->findOneBy(array('startVerse' => $verseId'level_id' => $this->STORY_LEVEL_ID_VERSE'isPublic' => true));
  1525.                 $illustrations = array();
  1526.                 $explanations = array();
  1527.                 if($verseStory != null)
  1528.                 {
  1529.                     $illustrations $verseStory->getIllustrations();
  1530.                     $explanations $verseStory->getExplanations(); 
  1531.                 } 
  1532.                 $templateData['verse_illustrations'] = $illustrations;
  1533.                                               
  1534.                 if(count($explanations) > && $explanations[0]->selectTranslation() != null && $explanations[0]->findFirstPassage() != null)
  1535.                 {                    
  1536.                     $templateData['verse_explanations'] = $explanations;                    
  1537.                     $nTempLanguageID $translation1['language_id'];    
  1538.                     $verseexplanation $this->getVerseExplanationInText($request$explanations$nTempLanguageID);
  1539.                     if(!empty($verseexplanation))
  1540.                     {                                            
  1541.                         $templateData['verse_explanation'] = $verseexplanation;                        
  1542.                         $templateData['passage_multilink'] = $this->getWorkPassageMultiLink($verseexplanation->findFirstNonEmptyPassage()->getId(),$verseexplanation->getId(), $request);
  1543.                         $templateData['authors'] = $this->getAuthorInfo($request$verseexplanation->getId());
  1544.                     }
  1545.                 }    
  1546.             } else {                
  1547.                 $templateData['explained_verse'] = $this->getFirstExplainedVerse($aVerseInfo$request);          
  1548.             } 
  1549.             
  1550.             $bInframe = (isset($templateData['in_frame']) && $templateData['in_frame']);
  1551.             $templateData['has_slider_item'] = $this->hasSliderItem($aVerseInfo$bInframe$request);
  1552.         
  1553.             $sSliderUrl "";
  1554. //    echo $verseStartIndex . ";;". $verseEndIndex;
  1555.             $sTranslationUrl $translation1['url'];
  1556.             $sBookUrl $canonicalBook->getUrl();
  1557.             if(empty($verseStartIndex) && empty($verseEndIndex))
  1558.             {
  1559.                 $sSliderUrl $this->get('router')->generate('bible_slider_chapter', array(
  1560.                     'translationUrl' => $sTranslationUrl,
  1561.                     'bookUrl' => $sBookUrl,
  1562.                     'chapterIndex' => $chapterStartIndex
  1563.                 ));    
  1564.             }
  1565.             elseif($bVerseLevel || empty($verseEndIndex))
  1566.             {
  1567.                 $sSliderUrl $this->get('router')->generate('bible_slider_verse', array(
  1568.                     'translationUrl' => $sTranslationUrl,
  1569.                     'bookUrl' => $sBookUrl,
  1570.                     'chapterIndex' => $chapterStartIndex,
  1571.                     'verseStartIndex' => $verseStartIndex
  1572.                 ));
  1573.             }
  1574.             else
  1575.             {
  1576.                 $sSliderUrl $this->get('router')->generate('bible_slider_verserange', array(
  1577.                     'translationUrl' => $sTranslationUrl,
  1578.                     'bookUrl' => $sBookUrl,
  1579.                     'chapterIndex' => $chapterStartIndex,
  1580.                     'verseStartIndex' => $verseStartIndex,
  1581.                     'verseEndIndex' => $verseEndIndex
  1582.                 ));
  1583.             }
  1584.             
  1585.             $templateData['slider_url'] = $sSliderUrl;
  1586.                                     
  1587.             $aOTLE $this->getOTLERefForBible($aVerseInfo, array(), true);  
  1588.       //      $templateData['otle_ref'] = $aOTLE['otle_nonmusic'];   
  1589.             $templateData['otle_ref_music'] = $aOTLE['otle_music'];
  1590.             
  1591.             $templateData['word_explanations'] = $this->getBibleWordExplanations($aVerseInfo$request);
  1592.             $templateData['word_explanations2'] = $this->getBibleWordExplanations($aVerseInfo2$request);
  1593.             
  1594.             
  1595.             
  1596.             $templateData['book_display_name'] = ($translation1['book_name'] !== null) ? $translation1['book_name'] : $translation2['book_name'];
  1597.             
  1598.             $templateData['book_url'] = $bookUrl;
  1599.               $templateData['translation_url'] = $translationUrl1;            
  1600.             
  1601.             $bookList $this->getBibleBookList($request$translation1['id'], $translation2['id']);
  1602. //            $templateData['book_list'] = $bookList;
  1603.             $nNextBookID $this->getNextBookID($translation1['book_id'], $bookList);
  1604.             $nPreviousBookID $this->getPreviousBookID($translation1['book_id'], $bookList);
  1605.             $templateData['next_chapter'] = $this->getNextChapter($nChapterID$nNextBookID);            
  1606.             $templateData['prev_chapter'] = $this->getPreviousChapter($nChapterID$nPreviousBookID);
  1607.                
  1608.             $templateData['qbible_link'] = $this->getQBibleLink2($canonicalBook$chapterStartIndex$verses1);
  1609.             
  1610.     //        if($chapterEndIndex == null && $verseStartIndex == null && $verseEndIndex == null)
  1611.     //        {          
  1612.                 $chapter current(current($canonicalVerseData))->getChapter();
  1613.                 $nCChapterID $chapter->getId(); 
  1614.                 $chapterExplanations $this->getChapterExplanation($nCChapterID$translationUrl1$request);
  1615.                   $templateData['chapter_explanation'] = $chapterExplanations;
  1616.                   $templateData['chapter_order'] = $chapter->getOrdering();
  1617.                   
  1618.                   if(!empty($chapterExplanations))
  1619.                   {
  1620.                           $nTransID current($chapterExplanations)['translation_id'];
  1621.                           $explanation_translation $this->expositionData('Translation')->findOneById($nTransID);
  1622.                           
  1623.                           if($explanation_translation != null)
  1624.                           {
  1625.                               $passage $explanation_translation->getWork()->findFirstNonEmptyPassage($explanation_translation);
  1626.                               if($passage != null)
  1627.                               {    
  1628.                                   $templateData['explanation_text_style_override'] = $this->getTextStyleOverride($nTransID);
  1629.                                   $templateData['explanation_translation'] = $explanation_translation;
  1630.                                   $templateData['explanation_passage'] = $passage;
  1631.                                   $templateData['explanation_authors'] = $this->getAuthorInfo($request$nTransID);
  1632.                                   $templateData['explanation_text_to_speech'] = $this->getTextToSpeech($explanation_translation->getLanguage()->getId());
  1633.                                   $templateData['passage_ref'] = $this->getWorkPassageRefs($passage->getId(),$nTransID$request);
  1634.                                   $templateData['passage_multilink'] = $this->getWorkPassageMultiLink($passage->getId(),$nTransID$request);
  1635.                                   $templateData['explanation_col1_ref'] = $this->MULTI_URL_INDICATOR_BIBLE "_" $translationUrl1 "_" $bookUrl "_" $templateData['chapter_order'];
  1636.                                   $templateData['explanation_col2_ref'] = $this->MULTI_URL_INDICATOR_EXPLANATION "_" $explanation_translation->getUrl();
  1637.                                   
  1638.                                   $nExplainChapterID $this->getExplainChapterID($nTransID$this->getCurrUserID($request));        
  1639.                                   if(!empty($nExplainChapterID))
  1640.                                   {
  1641.                                       $templateData['explanation_cchapter_id'] = $nCChapterID;  
  1642.                                       $templateData['explanation_translation_id'] = $nTransID;                         
  1643.                                   }    
  1644.                               }
  1645.                           }    
  1646.                   }
  1647.       //      }
  1648.          
  1649.              $this->setCurrentUrl($request);
  1650.              $templateData['linktype_id'] = $this->LINK_TYPE_ID_BIBLE;       
  1651.             return $this->renderView('comparison/span'$templateData$response);
  1652.         }
  1653.     }
  1654.     public function quickviewVerseAction($verseIdRequest $request)
  1655.     {
  1656.         $this->onloadPage($request);
  1657.         $verse $this->bibleData('Verse')->findOneById($verseId);
  1658.         return $this->chapterQuickview($verse->getChapter());
  1659.     }
  1660.     public function quickviewChapterAction($chapterIdRequest $request)
  1661.     {
  1662.         $this->onloadPage($request);
  1663.         return $this->chapterQuickview($this->bibleData('Chapter')->findOneById($chapterId));
  1664.     }
  1665.     
  1666.     public function quickviewTranslationChapterAction($translationId$chapterIdRequest $request)
  1667.     {
  1668.         $this->onloadPage($request);
  1669.         $new_chapterId $this->getChapterIDForTranslation($translationId$chapterId);
  1670.     
  1671.         return $this->chapterQuickview($this->bibleData('Chapter')->findOneById($new_chapterId));
  1672.     }
  1673.     protected function chapterQuickview($chapter)
  1674.     {
  1675.         $response null;
  1676.         if($chapter === null) {
  1677.             $response = new Response();
  1678.             $response->setStatusCode(404);
  1679.             return $this->renderView('no_content', array(), $response);            
  1680.         }
  1681.     
  1682.         $book $chapter->getBook();
  1683.         $verses $chapter->getVerses();     
  1684.         $quickviewData = array(
  1685.             'book' => ($chapter === null) ? null $book,
  1686.             'contents' => ($chapter === null) ? array() : array($chapter->getOrdering() => $verses),
  1687.             'chapter_id' => ($chapter === null) ? null $chapter->getId(),
  1688.             'prev_chapter' => ($chapter === null) ? null $this->getPreviousChapter($chapter->getId()),
  1689.             'next_chapter' => ($chapter === null) ? null $this->getNextChapter($chapter->getId())            
  1690.         );
  1691.         
  1692.         $sFirstVerseIndex "";
  1693.         $sLastVerseIndex "";
  1694.         foreach($verses as $v)
  1695.         {            
  1696.             if($sFirstVerseIndex == "")
  1697.                 $sFirstVerseIndex $v->getIndexDisplay();
  1698.                 
  1699.             $sLastVerseIndex $v->getIndexDisplay();    
  1700.         }     
  1701.         
  1702.         $quickviewData['translations_by_language'] = $this->getBibleTranslationsByLanguageForVerses($book->getCanonicalization()->getId(), $chapter->getOrdering(), $sFirstVerseIndex$chapter->getOrdering(), $sLastVerseIndex);        
  1703.            
  1704.         return $this->renderView('quickview/verse_range'$quickviewData$response);
  1705.     }
  1706.     protected function getChapterPath($translationUrl$bookUrl$chapterIndex$request$setCurrentLanguage false)
  1707.     {
  1708.     //  $this->logtime(' T:getChapterPath:  enter');
  1709.         $rval['book'] = $this->getBookByUrl($translationUrl$bookUrl$request$setCurrentLanguage);        
  1710.         if($rval['book'] === null) {
  1711.             $rval['chapter'] = null;
  1712.             $rval['translation'] = $this->bibleData('Translation')->findOneBy(array('url' => $translationUrl'enabled' => true));
  1713.         } else {
  1714.             $rval['chapter'] = $this->bibleData('Chapter')->findOneBy(array('book' => $rval['book']->getId(), 'ordering' => $chapterIndex));
  1715.         }
  1716.         $rval['canonical_book'] = $this->bibleData('Canonical\Book')->findOneByUrl(TextFormatter::urlify($bookUrl));
  1717.     //$this->logtime(' T:getChapterPath:  exit');
  1718.         return $rval;    
  1719.     }
  1720.     /**
  1721.      * $userSelected is true if the user specifically wanted to view this translation, false if the translation was chosen for the user
  1722.      * (which is usually the case with an excerpt, since the excerpt is from a specific translation)
  1723.      */
  1724.     public function excerptAction($excerptIdRequest $request$userSelected false)
  1725.     {
  1726.         $this->checkIfOnMobile($request);
  1727.         $excerpt $this->bibleData('Excerpt')->findOneById($excerptId);
  1728.         if($excerpt !== null) {
  1729.             $startVerse $excerpt->getStartVerse();
  1730.             $endVerse $excerpt->getEndVerse();
  1731.             $book $startVerse->findMainVerse()->getChapter()->getBook();
  1732.             $excerptContents $book->getVerseList($startVerse$endVerse);
  1733.             if($userSelected) {
  1734.                 $request->getSession()->set('current_language'$book->getTranslation()->getLanguage()->getBibliographicCode());
  1735.             }
  1736.   
  1737.               $aVerse array_reduce($excerptContents'array_merge', array());
  1738.               $aVerseInfo $this->getVerseInfo($aVerse);
  1739.                  
  1740.             $aOTLE $this->getOTLERefForBible($aVerseInfo, array(), true);   
  1741.         //    $otle_ref = $aOTLE['otle_nonmusic']; 
  1742.             $otle_ref_music $aOTLE['otle_music'];
  1743.             
  1744.             $bHasSliderItem $this->hasSliderItem($aVerseInfofalse$request);
  1745.             
  1746.             $response null;
  1747.         } else {
  1748.             $startVerse null;
  1749.             $endVerse null;
  1750.             $book null;
  1751.             $excerptContents = array();
  1752.      //       $referringPassages = array();
  1753.      //       $corePassages = array();
  1754.             $response = new Response();
  1755.             $response->setStatusCode(404);
  1756.         }
  1757.         if($startVerse->getId() == $endVerse->getId()) {
  1758.             return $this->renderView('excerpt_verse', array(
  1759.                 'verse' => $startVerse,
  1760.                 'excerpt_text' => substr($startVerse->getContent(), $excerpt->getStartChar(), $excerpt->getEndChar()-$excerpt->getStartChar()+1),
  1761.                 'has_slider_item' => $bHasSliderItem,        
  1762.                   'otle_ref_music' => $otle_ref_music
  1763.             ), $response);
  1764.         }
  1765.         return $this->renderView('excerpt_book', array(
  1766.             'book' => $book,
  1767.             'excerpt_contents' => $excerptContents,
  1768.             'begin_text' => substr($startVerse->getContent(), $excerpt->getStartChar()),
  1769.             'end_text' => substr($endVerse->getContent(), 0$excerpt->getEndChar()+1),
  1770.             'has_slider_item' => $bHasSliderItem    
  1771.         ), $response);
  1772.     }
  1773.     
  1774.     protected function isRightToLeft($translationUrl) {
  1775.         $translation $this->getTranslationByUrlNoOption($translationUrl);
  1776.         $bRightToLeft false;
  1777.         if($translation != null)
  1778.         {
  1779.             $language $translation->getLanguage();
  1780.             $bRightToLeft $language->getRightToLeft();
  1781.         }
  1782.         
  1783.         return $bRightToLeft;
  1784.     }
  1785.     
  1786.     public function compareVerses3colAction($translationUrl1$translationUrl2$translationUrl3$bookUrl$chapterStartIndexRequest $request$chapterEndIndex null$verseStartIndex null$verseEndIndex null)
  1787.     {
  1788.         $this->checkIfOnMobile($request);
  1789.         $msgData $this->checkBibleTranslationMsg($translationUrl1); 
  1790.         if(empty($msgData))
  1791.             $msgData $this->checkBibleTranslationMsg($translationUrl2);
  1792.         if(empty($msgData))
  1793.             $msgData $this->checkBibleTranslationMsg($translationUrl3);    
  1794.             
  1795.       if(!empty($msgData))
  1796.       {
  1797.           $response = new Response();
  1798.         $response->setStatusCode(404);
  1799.           return $this->renderView('no_content'$msgData$response);
  1800.       }    
  1801.          
  1802.         $this->onloadPage($request);          
  1803.         $translation1 $this->getBibleTranslationInfo($translationUrl1$bookUrl);
  1804.         $translation2 $this->getBibleTranslationInfo($translationUrl2$bookUrl);
  1805.         $translation3 $this->getBibleTranslationInfo($translationUrl3$bookUrl);
  1806.         
  1807.         if(empty($translation1) || empty($translation2) || empty($translation3))
  1808.         {
  1809.             $response = new Response();
  1810.             $response->setStatusCode(404);
  1811.             return $this->renderView('no_content_back', array(), $response);
  1812.         } 
  1813.         
  1814.         if($chapterStartIndex != null)
  1815.         {
  1816.             $lastChapterNumBook1 $translation1['last_chapter_order'];
  1817.             if($lastChapterNumBook1 $chapterStartIndex)
  1818.             {
  1819.                 $response = new Response();
  1820.                 $response->setStatusCode(404);
  1821.                 return $this->renderView('no_chapter_back', array(), $response);
  1822.             }
  1823.         
  1824.             $lastChapterNumBook2 $translation2['last_chapter_order'];
  1825.             if($lastChapterNumBook2 $chapterStartIndex)
  1826.             {
  1827.                 $response = new Response();
  1828.                 $response->setStatusCode(404);
  1829.                 return $this->renderView('no_chapter_back', array(), $response);
  1830.             }
  1831.             
  1832.             $lastChapterNumBook3 $translation3['last_chapter_order'];
  1833.             if($lastChapterNumBook3 $chapterStartIndex)
  1834.             {
  1835.                 $response = new Response();
  1836.                 $response->setStatusCode(404);
  1837.                 return $this->renderView('no_chapter_back', array(), $response);
  1838.             }
  1839.         }
  1840.         
  1841.         $bVerseLevel false;
  1842.         
  1843.         $locale $request->getLocale();
  1844.         $nLanguageID $this->getLanguageIDByShortCode($locale);
  1845.         
  1846.         $bible_column_spec $this->getMultiColumnSpecForChapterRange($translationUrl1$bookUrl$chapterStartIndex$chapterEndIndex$verseStartIndex$verseEndIndex);
  1847.         
  1848.         $right_to_left1 $translation1['righttoleft'];
  1849.         $right_to_left2 $translation2['righttoleft'];
  1850.         $right_to_left3 $translation3['righttoleft'];
  1851.     
  1852.         $canonicalBook $this->bibleData('Canonical\Book')->findOneByUrl($bookUrl);
  1853.            
  1854.         $canonicalVerseData DataAssembly::getVerseRangeFromBook($canonicalBook$chapterStartIndex$chapterEndIndex$verseStartIndex$verseEndIndex);
  1855.         $verses1 DataAssembly::decanonicalizeSpan($this->getManager(), $translation1['id'], $canonicalVerseData);
  1856.         $verses2 DataAssembly::decanonicalizeSpan($this->getManager(), $translation2['id'], $canonicalVerseData);
  1857.         $verses3 DataAssembly::decanonicalizeSpan($this->getManager(), $translation3['id'], $canonicalVerseData);
  1858.         
  1859.         $aVerse array_reduce($verses1'array_merge', array());
  1860.         $aVerse2 array_reduce($verses2'array_merge', array());
  1861.         $aVerse3 array_reduce($verses3'array_merge', array());
  1862.         
  1863.         $templateData = array(
  1864.             'translation1' => $translation1,            
  1865.             'contents1' => $verses1,
  1866.             'translation2' => $translation2,            
  1867.             'contents2' => $verses2,
  1868.             'translation3' => $translation3,            
  1869.             'contents3' => $verses3,
  1870.             'translations_by_language' => $this->getBibleTranslationsByLanguage($canonicalBook->getId(), $nLanguageID),
  1871.             'verses_concept1' => $this->getVerseContentWithConceptLinks($request$aVerse$bible_column_spec),
  1872.             'verses_concept2' => $this->getVerseContentWithConceptLinks($request$aVerse2$bible_column_spec2),
  1873.             'verses_concept3' => $this->getVerseContentWithConceptLinks($request$aVerse3$bible_column_spec3),
  1874.             'canonical_book' => $canonicalBook,
  1875.             'contents_canonical' => $canonicalVerseData,
  1876.             'canonical_chapter_start' => $chapterStartIndex,
  1877.             'canonical_chapter_end' => $chapterEndIndex,
  1878.             'canonical_verse_start' => $verseStartIndex,
  1879.             'canonical_verse_end' => $verseEndIndex,
  1880.             'right_to_left1' => $right_to_left1,
  1881.             'right_to_left2' => $right_to_left2,
  1882.             'right_to_left3' => $right_to_left3,
  1883.             'text_style_override1' => $this->getTextStyleOverrideForBible($translation1['book_id']),
  1884.             'text_style_override2' => $this->getTextStyleOverrideForBible($translation2['book_id']),
  1885.             'text_style_override3' => $this->getTextStyleOverrideForBible($translation3['book_id']),
  1886.             'text_to_speech1' => $this->getTextToSpeech($translation1['language_id']),
  1887.             'text_to_speech2' => $this->getTextToSpeech($translation2['language_id']),
  1888.             'text_to_speech3' => $this->getTextToSpeech($translation3['language_id'])
  1889.         );
  1890.         
  1891.         $templateData['bible_column_spec1'] = $this->getMultiColumnSpecForChapterRange($translationUrl1$bookUrl$chapterStartIndex$chapterEndIndex$verseStartIndex$verseEndIndex);
  1892.         $templateData['bible_column_spec2'] = $this->getMultiColumnSpecForChapterRange($translationUrl2$bookUrl$chapterStartIndex$chapterEndIndex$verseStartIndex$verseEndIndex);
  1893.         $templateData['bible_column_spec3'] = $this->getMultiColumnSpecForChapterRange($translationUrl3$bookUrl$chapterStartIndex$chapterEndIndex$verseStartIndex$verseEndIndex);
  1894.         
  1895.         $bEmptyContent1 = empty($templateData['contents1']);                
  1896.         $bEmptyContent2 = empty($templateData['contents2']);
  1897.         $bEmptyContent3 = empty($templateData['contents3']);
  1898.         $response null;
  1899.         if($bEmptyContent1 || $bEmptyContent2 || $bEmptyContent3)
  1900.         {
  1901.             $response = new Response();
  1902.             $response->setStatusCode(404);
  1903.             return $this->renderView('no_content_back', array(), $response);
  1904.         } 
  1905.         else
  1906.         {
  1907.             $aVerseInfo $this->getVerseInfo($aVerse);
  1908.             $aVerseInfo2 $this->getVerseInfo($aVerse2);
  1909.             $aVerseInfo3 $this->getVerseInfo($aVerse3);
  1910.             
  1911.             $nChapterID $aVerseInfo['FirstChapterID'];
  1912.             
  1913.        //     $templateData['verse_story'] = $this->getStoriesForVerses($aVerseInfo, $request);
  1914.     
  1915.             // If we have a single (canonical) verse, we'll check if it has an explanation; otherwise, we'll look for verses that have explanations
  1916.             if($chapterEndIndex === null && $verseStartIndex !== null && ($verseEndIndex === null || $verseEndIndex <= $verseStartIndex)) {
  1917.                 $bVerseLevel true;
  1918.                 $chapterList reset($canonicalVerseData);
  1919.                 $verse reset($chapterList);
  1920.                 $verseId $verse->getId();
  1921.                 $verseStory $this->bibleData('Stories\Story')->findOneBy(array('startVerse' => $verseId'level_id' => $this->STORY_LEVEL_ID_VERSE'isPublic' => true));
  1922.                 $illustrations = array();
  1923.                 $explanations = array();
  1924.                 if($verseStory != null)
  1925.                 {
  1926.                     $illustrations $verseStory->getIllustrations();
  1927.                     $explanations $verseStory->getExplanations();   
  1928.                 } 
  1929.                 $templateData['verse_illustrations'] = $illustrations;
  1930.                 
  1931.                 if(count($explanations) > && $explanations[0]->selectTranslation() != null && $explanations[0]->findFirstPassage() != null)
  1932.                 {                    
  1933.                     $templateData['verse_explanations'] = $explanations;
  1934.                     
  1935.                     $nTempLanguageID $translation1['language_id'];
  1936.                     $verseexplanation $this->getVerseExplanationInText($request$explanations$nTempLanguageID);
  1937.                     if(!empty($verseexplanation))
  1938.                     {                                            
  1939.                         $templateData['verse_explanation'] = $verseexplanation;                        
  1940.                         $templateData['passage_multilink'] = $this->getWorkPassageMultiLink($verseexplanation->findFirstNonEmptyPassage()->getId(),$verseexplanation->getId(), $request);
  1941.                         $templateData['authors'] = $this->getAuthorInfo($request$verseexplanation->getId());
  1942.                     }
  1943.                 }    
  1944.             } else {                               
  1945.                 $templateData['explained_verse'] = $this->getFirstExplainedVerse($aVerseInfo$request);           
  1946.             }
  1947.             
  1948.             $bInframe = (isset($templateData['in_frame']) && $templateData['in_frame']);
  1949.             $templateData['has_slider_item'] = $this->hasSliderItem($aVerseInfo$bInframe$request);   
  1950.             $sSliderUrl "";
  1951. //    echo $verseStartIndex . ";;". $verseEndIndex;
  1952.             $sTranslationUrl $translation1['url'];
  1953.             $sBookUrl $canonicalBook->getUrl();
  1954.             if(empty($verseStartIndex) && empty($verseEndIndex))
  1955.             {
  1956.                 $sSliderUrl $this->get('router')->generate('bible_slider_chapter', array(
  1957.                     'translationUrl' => $sTranslationUrl,
  1958.                     'bookUrl' => $sBookUrl,
  1959.                     'chapterIndex' => $chapterStartIndex
  1960.                 ));    
  1961.             }
  1962.             elseif($bVerseLevel || empty($verseEndIndex))
  1963.             {
  1964.                 $sSliderUrl $this->get('router')->generate('bible_slider_verse', array(
  1965.                     'translationUrl' => $sTranslationUrl,
  1966.                     'bookUrl' => $sBookUrl,
  1967.                     'chapterIndex' => $chapterStartIndex,
  1968.                     'verseStartIndex' => $verseStartIndex
  1969.                 ));
  1970.             }
  1971.             else
  1972.             {
  1973.                 $sSliderUrl $this->get('router')->generate('bible_slider_verserange', array(
  1974.                     'translationUrl' => $sTranslationUrl,
  1975.                     'bookUrl' => $sBookUrl,
  1976.                     'chapterIndex' => $chapterStartIndex,
  1977.                     'verseStartIndex' => $verseStartIndex,
  1978.                     'verseEndIndex' => $verseEndIndex
  1979.                 ));
  1980.             }
  1981.             
  1982.             $templateData['slider_url'] = $sSliderUrl;
  1983.                               
  1984.             $aOTLE $this->getOTLERefForBible($aVerseInfo, array(), true); 
  1985.         //    $templateData['otle_ref'] = $aOTLE['otle_nonmusic'];   
  1986.             $templateData['otle_ref_music'] = $aOTLE['otle_music'];
  1987.             
  1988.             $templateData['word_explanations'] = $this->getBibleWordExplanations($aVerseInfo$request);
  1989.             $templateData['word_explanations2'] = $this->getBibleWordExplanations($aVerseInfo2$request);
  1990.             $templateData['word_explanations3'] = $this->getBibleWordExplanations($aVerseInfo3$request);
  1991.             
  1992.     
  1993.             $templateData['book_display_name'] = ($translation1['book_name'] !== null) ? $translation1['book_name'] : $translation2['book_name'];
  1994.             
  1995.             $templateData['book_url'] = $bookUrl;
  1996.               $templateData['translation_url'] = $translationUrl1;
  1997.             
  1998.             $bookList $this->getBibleBookList($request$translation1['id'], $translation2['id'], $translation3['id']);
  1999. //            $templateData['book_list'] = $bookList;
  2000.             $nNextBookID $this->getNextBookID($translation1['book_id'], $bookList);
  2001.             $nPreviousBookID $this->getPreviousBookID($translation1['book_id'], $bookList);
  2002.             $templateData['next_chapter'] = $this->getNextChapter($nChapterID$nNextBookID);            
  2003.             $templateData['prev_chapter'] = $this->getPreviousChapter($nChapterID$nPreviousBookID);
  2004.             
  2005.             $templateData['qbible_link'] = $this->getQBibleLink2($canonicalBook$chapterStartIndex$verses1);
  2006.             
  2007.       //      if($chapterEndIndex == null && $verseStartIndex == null && $verseEndIndex == null)
  2008.       //      {          
  2009.                 $chapter current(current($canonicalVerseData))->getChapter();
  2010.                 $nCChapterID $chapter->getId(); 
  2011.                 $chapterExplanations $this->getChapterExplanation($nCChapterID$translationUrl1$request);
  2012.                   $templateData['chapter_explanation'] = $chapterExplanations;
  2013.                   $templateData['chapter_order'] = $chapter->getOrdering();                  
  2014.                   if(!empty($chapterExplanations))
  2015.                   {
  2016.                           $nTransID current($chapterExplanations)['translation_id'];
  2017.                           $explanation_translation $this->expositionData('Translation')->findOneById($nTransID);
  2018.                           
  2019.                           if($explanation_translation != null)
  2020.                           {
  2021.                               $passage $explanation_translation->getWork()->findFirstNonEmptyPassage($explanation_translation);
  2022.                               if($passage != null)
  2023.                               {    
  2024.                                   $templateData['explanation_text_style_override'] = $this->getTextStyleOverride($nTransID);
  2025.                                   $templateData['explanation_translation'] = $explanation_translation;
  2026.                                   $templateData['explanation_passage'] = $passage;
  2027.                                   $templateData['explanation_authors'] = $this->getAuthorInfo($request$nTransID);
  2028.                                   $templateData['explanation_text_to_speech'] = $this->getTextToSpeech($explanation_translation->getLanguage()->getId());
  2029.                                   $templateData['passage_ref'] = $this->getWorkPassageRefs($passage->getId(),$nTransID$request);
  2030.                                   $templateData['passage_multilink'] = $this->getWorkPassageMultiLink($passage->getId(),$nTransID$request);
  2031.                                   $templateData['explanation_col1_ref'] = $this->MULTI_URL_INDICATOR_BIBLE "_" $translationUrl1 "_" $bookUrl "_" $templateData['chapter_order'];
  2032.                                   $templateData['explanation_col2_ref'] = $this->MULTI_URL_INDICATOR_EXPLANATION "_" $explanation_translation->getUrl();
  2033.                                   
  2034.                                   $nExplainChapterID $this->getExplainChapterID($nTransID$this->getCurrUserID($request));        
  2035.                                   if(!empty($nExplainChapterID))
  2036.                                   {
  2037.                                       $templateData['explanation_cchapter_id'] = $nCChapterID;  
  2038.                                       $templateData['explanation_translation_id'] = $nTransID;                         
  2039.                                   }    
  2040.                               }
  2041.                           }    
  2042.                   }
  2043.           //  }
  2044.             
  2045.             $this->setCurrentUrl($request);             
  2046.             return $this->renderView('comparison/span3col'$templateData$response);
  2047.         }
  2048.     }
  2049.     private function logtime($msg)
  2050.     {
  2051.       $tparts explode(' ',microtime());
  2052.       $s = ($tparts[1] % 10) + $tparts[0];
  2053.       $logger $this->get('logger');
  2054.       // TODO: test if env is prod..
  2055.       // don't run in prod
  2056.       if ( $this->get('kernel')->getEnvironment() == 'dev' ) {
  2057.     $logger->info(  sprintf'%2.5f %s'$s$msg) );
  2058.       }
  2059.       //error_log( sprintf( '%2.5f %s', $s, $msg) );
  2060.       //  or only log for time > threshold
  2061.     }
  2062.         
  2063.     function getQBibleLink($book$chapter$verses)
  2064.     {
  2065.         $cbook $book->getCanonicalization();
  2066.         $nCBookId $cbook->getId();
  2067.         $nChapterOrder $chapter->getOrdering();
  2068.         $nVerseOrder 1;
  2069.         foreach($verses as $key => $val) {
  2070.             if(!is_array($val)) {
  2071.                 $nVerseOrder $val->getIndexDisplay();  
  2072.                 break;              
  2073.             }
  2074.         }
  2075.                        
  2076.         $nTestmentId $cbook->getTestament()->getId();
  2077.         $sLinkStart '';
  2078.         if($nTestmentId == 1// old testament
  2079.             $sLinkStart 'http://qbible.com/hebrew-old-testament/';
  2080.         else
  2081.             $sLinkStart 'http://qbible.com/greek-new-testament/';    
  2082.     
  2083.         return $this->getNativeQueryResults("SELECT '" $sLinkStart "' || qbible_url || '/' || '" $nChapterOrder "' || '.html#' || '" $nVerseOrder "' as url from canonicalbiblebook"                
  2084.                 ." WHERE id = " $nCBookId " and qbible_url is not null and qbible_url <> ''");
  2085.     } 
  2086.     
  2087.     function getQBibleLink2($cbook$nChapterOrder$verses)
  2088.     {        
  2089.         $nCBookId $cbook->getId();        
  2090.         $nVerseOrder 1;
  2091.         foreach($verses as $key => $val) {
  2092.             if(!is_array($val)) {
  2093.                 $nVerseOrder $val->getIndexDisplay();  
  2094.                 break;              
  2095.             }
  2096.         }
  2097.                        
  2098.         $nTestmentId $cbook->getTestament()->getId();
  2099.         $sLinkStart '';
  2100.         if($nTestmentId == 1// old testament
  2101.             $sLinkStart 'http://qbible.com/hebrew-old-testament/';
  2102.         else
  2103.             $sLinkStart 'http://qbible.com/greek-new-testament/';    
  2104.     
  2105.         return $this->getNativeQueryResults("SELECT '" $sLinkStart "' || qbible_url || '/' || '" $nChapterOrder "' || '.html#' || '" $nVerseOrder "' as url from canonicalbiblebook"                
  2106.                 ." WHERE id = " $nCBookId " and qbible_url is not null and qbible_url <> ''");
  2107.     } 
  2108.          
  2109.     function getMultiColumnSpecForChapterRange($translationUrl$bookUrl$chapterStartIndex$chapterEndIndex$verseStartIndex=null$verseEndIndex null)
  2110.     {
  2111.         $bible_multi_spec $this->MULTI_URL_INDICATOR_BIBLE '_' $translationUrl '_' $bookUrl;
  2112.         if($chapterStartIndex != null)
  2113.         {
  2114.             $bible_multi_spec .= '_' $chapterStartIndex;
  2115.             if($chapterEndIndex != null)
  2116.               $bible_multi_spec .= '-' $chapterEndIndex;
  2117.           
  2118.           if($verseStartIndex != null)
  2119.           {
  2120.               $bible_multi_spec .= '_' $verseStartIndex;
  2121.               if($verseEndIndex != null)
  2122.                   $bible_multi_spec .= '-' $verseEndIndex;
  2123.           }    
  2124.         }
  2125.         return $bible_multi_spec;
  2126.     }
  2127.     
  2128.     public function readingPlanIndexAction(Request $request)
  2129.     {            
  2130.         $this->setCurrentUrl($request); 
  2131.         $this->onloadPage($request);        
  2132.         $locale $request->getLocale();        
  2133.         $nUserID $request->getSession()->get("user_id");        
  2134.         $list $this->getReadingPlanList($nUserID$locale);        
  2135.         $data = array(
  2136.             'plan_data' => $list       
  2137.         );
  2138.         
  2139.         return $this->renderView('reading_plan_index'$data);
  2140.     }
  2141.     
  2142.     public function readingPlanAction($readingPlanUrlRequest $request)
  2143.     {
  2144.         $this->onloadPage($request);
  2145.         $this->setCurrentUrl($request);    
  2146.         $locale $request->getLocale();
  2147.         $info $this->getReadingPlanInfo($readingPlanUrl,$locale);   
  2148.         $nUserID $request->getSession()->get("user_id");
  2149.         $user_plan null;
  2150.         
  2151.         $nTextLength 150;
  2152.         $sMetaDesc $this->getTextWithinLength($info['description'], $nTextLength"...");
  2153.         $aReminderOption = array();
  2154.         if(!empty($nUserID))
  2155.         {
  2156.             $aReminderOption $this->getReminderOptionList($request);
  2157.         }
  2158.         
  2159.         $data = array(
  2160.             'reading_plan' => $info,
  2161.             'meta_desc' => $sMetaDesc,
  2162.             'reminder_options' => $aReminderOption      
  2163.         );
  2164.                 
  2165.         $data['user_plan'] = $this->getUserReadingPlanInfo($readingPlanUrl,$nUserID$request);      
  2166.                 
  2167.         return $this->renderView('reading_plan'$data);
  2168.     }
  2169.     
  2170.     public function readingPlanStepsAction($readingPlanUrlRequest $request)
  2171.     {
  2172.         $this->onloadPage($request);
  2173.         $nUserID $request->getSession()->get("user_id");
  2174.         if($nUserID == '')
  2175.         {
  2176.         }
  2177.         else
  2178.         {             
  2179.             $user_plan $this->getUserReadingPlanInfo($readingPlanUrl,$nUserID$request); 
  2180.             $step_order $user_plan['step_order']; 
  2181.         }   
  2182.               
  2183.         return $this->redirect($this->get('router')->generate('reading_plan_step', array(
  2184.                         'readingPlanUrl' => $readingPlanUrl,
  2185.                         'stepOrder' => $step_order
  2186.                     )), 301); 
  2187.     }
  2188.     
  2189.     public function readingPlanStepAction($readingPlanUrl$stepOrderRequest $request$translationUrl null)
  2190.     {                 
  2191.          $rps $this->getReadingPlanStepBasicInfo($readingPlanUrl$stepOrder$request);
  2192.         if(empty($rps)) {
  2193.             $response = new Response();
  2194.             $response->setStatusCode(404);
  2195.             return $this->renderView('no_content', array(), $response);
  2196.         }
  2197.         
  2198.         $this->onloadPage($request);
  2199.         $this->setCurrentUrl($request);
  2200.         $nUserID $request->getSession()->get("user_id");
  2201.         $nStart null;
  2202.         if($nUserID == '')
  2203.         {
  2204.         
  2205.         }
  2206.         else
  2207.         {                        
  2208.             $nStart $request->query->get('s');
  2209.             if(!empty($nStart))            
  2210.                 $request->getSession()->set("reading_plan_started"$nStart);        
  2211.         }
  2212.         
  2213.         $nTypeID $rps['type_id'];
  2214.         if($nTypeID == $this->READINGPLAN_STEP_TYPE_ID_ADHOC)
  2215.         {       
  2216.              $plan_step $rps;                             
  2217.              return $this->readingplanStepForAdhoc($readingPlanUrl$plan_step$request);
  2218.         }
  2219.         else if($nTypeID != $this->READINGPLAN_STEP_TYPE_ID_BIBLE)
  2220.         {             
  2221.             $work_id "";
  2222.             if($nTypeID == $this->READINGPLAN_STEP_TYPE_ID_SWEDENBORG_WORK)
  2223.                 $work_id $rps['work_id'];
  2224.             else
  2225.                 $work_id $rps['explanation_id'];
  2226.                 
  2227.              if($translationUrl === null) {
  2228.                  $sTranslationUrl ""
  2229.                  if($work_id == $request->getSession()->get("current_reading_plan_work_id"))
  2230.                  {
  2231.                      $sTranslationUrl $request->getSession()->get("current_reading_plan_work_translation_url");
  2232.                  }
  2233.                  
  2234.                  if($sTranslationUrl == '')
  2235.                  {    
  2236.                     $trans $this->getDefaultWorkTranslation($work_id$request);
  2237.                     $sTranslationUrl $trans['url'];
  2238.                 }
  2239.                 return $this->redirect($this->get('router')->generate('reading_plan_step_translated', array(
  2240.                     'readingPlanUrl' => $readingPlanUrl,
  2241.                     'stepOrder' => $stepOrder,
  2242.                     'translationUrl' => $sTranslationUrl
  2243.                 )), 301); 
  2244.             }
  2245.                           
  2246.              $passage_id $rps['passage_id'];
  2247.              $plan_step $rps;                             
  2248.              return $this->readingplanStepForWork($translationUrl$work_id$passage_id$readingPlanUrl$plan_step$request);
  2249.         }
  2250.         else
  2251.         {
  2252.             $readingPlanStep $this->getReadingPlanStepInfoForBible($readingPlanUrl$stepOrder$request);
  2253.             if($translationUrl === null) {
  2254.                 // For SEO purposes, we'll send the visitor to the route for the Plan step with the default translation
  2255.                 $sTranslationUrl ""
  2256.                  if($request->getSession()->get("current_reading_plan_bible_translation_url") != '')
  2257.                  {
  2258.                      $sTranslationUrl $request->getSession()->get("current_reading_plan_bible_translation_url");
  2259.                  }
  2260.                  
  2261.                  if($sTranslationUrl == '')
  2262.                  {    
  2263.                     $bibletrans $this->getDefaultBibleTranslation($readingPlanStep['book_id'], $request);
  2264.                     $sTranslationUrl $bibletrans['url'];
  2265.                 }
  2266.                 
  2267.                 return $this->redirect($this->get('router')->generate('reading_plan_step_translated', array(
  2268.                     'readingPlanUrl' => $readingPlanUrl,
  2269.                     'stepOrder' => $stepOrder,
  2270.                     'translationUrl' => $sTranslationUrl
  2271.                 )), 301); 
  2272.             }
  2273.                                               
  2274.             $translation $this->bibleData('Translation')->findOneBy(array('url' => $translationUrl'enabled' => true));                
  2275.             if($translation === null) {
  2276.                 $response = new Response();
  2277.                 $response->setStatusCode(404);
  2278.                 return $this->renderView('no_content', array(), $response);
  2279.             }   
  2280.             
  2281.             if($translationUrl != null)
  2282.             {
  2283.                 $request->getSession()->set("current_reading_plan_bible_translation_url"$translationUrl);
  2284.             }
  2285.                             
  2286.             $right_to_left $translation->getLanguage()->getRightToLeft();    
  2287.                         
  2288.             $canonicalStartVerseOrder $readingPlanStep['start_verse_order'];
  2289.             $canonicalEndVerseOrder $readingPlanStep['end_verse_order'];
  2290.             $canonicalStartChapterOrder $readingPlanStep['start_chapter_order'];
  2291.             $canonicalEndChapterOrder $readingPlanStep['end_chapter_order'];       
  2292.             $canonicalBook $this->bibleData('Canonical\Book')->findOneBy(array('id' => $readingPlanStep['book_id'])); 
  2293.             
  2294.             $contentsCanonical DataAssembly::getVerseRangeFromBook($canonicalBook$canonicalStartChapterOrder$canonicalEndChapterOrder$canonicalStartVerseOrder$canonicalEndVerseOrder);
  2295.             $contents DataAssembly::decanonicalizeSpan($this->getManager(), $translation->getId(), $contentsCanonical);
  2296.             if(count($contents) === 0) {
  2297.                 // Content does not exist in this translation
  2298.                 $response = new Response();
  2299.                 $response->setStatusCode(404);
  2300.                 return $this->renderView('no_content', array(), $response);
  2301.             } else {       
  2302.                 $firstChapterContents reset($contents);
  2303.                 $firstVerse reset($firstChapterContents);
  2304.                 $firstChapter $firstVerse->findMainVerse()->getChapter();
  2305.                 $lastChapterContents end($contents);
  2306.                 $lastVerse end($lastChapterContents);
  2307.                 $lastChapter $lastVerse->findMainVerse()->getChapter();
  2308.                 $completeChapters $firstVerse === $firstChapter->getVerses()->first() && $lastVerse === $lastChapter->getVerses()->last();
  2309.                 $planStepData = array(
  2310.                     'plan_step' => $readingPlanStep,                
  2311.                     'translation' => $translation,
  2312.                     'book' => $firstVerse->findMainVerse()->getChapter()->getBook(),
  2313.                     'content_class' => 'planstep',
  2314.                     'right_to_left' => $right_to_left
  2315.                 );
  2316.                 
  2317.            //     $planStepData['next_chapter'] = $this->getNextChapter($firstChapter->getId());
  2318.           //        $planStepData['prev_chapter'] = $this->getPreviousChapter($firstChapter->getId());
  2319.           
  2320.                   $bSingleVerse = ($firstVerse == $lastVerse);
  2321.                   if($bSingleVerse)
  2322.                     $planStepData['content_type'] = 'single_verse';
  2323.                 else
  2324.                     $planStepData['content_type'] = 'verseRange';
  2325.                   
  2326.                   $nContentNum 0;
  2327.                   foreach($contents as $c)
  2328.                   {
  2329.                       $nContentNum += count($c);
  2330.                   }
  2331.                   
  2332.                   $bShowBottomNav = ($nContentNum >= 6);
  2333.              
  2334.                 $bSingleChapter false;
  2335.                 if(count($contents) === 1) {
  2336.                     // Plan step is entirely within a single chapter
  2337.                     $bSingleChapter true;
  2338.                     $planStepData['chapter'] = $firstChapter;
  2339.                     if($bSingleVerse)
  2340.                     {
  2341.                         $planStepData['verse'] = $firstVerse;
  2342.                         $planStepData['verse_index'] = $canonicalStartVerseOrder;
  2343.                     }
  2344.                     $planStepData['verses'] = $firstChapterContents;
  2345.                             
  2346.                     if(!$completeChapters) {
  2347.                         $planStepData['verses_last_index'] = $lastVerse->getFullIndexDisplay();
  2348.                     }
  2349.                 //    $planStepData['content_type'] = 'verseRange';  
  2350.                    
  2351.                     $planStepData['slider_url'] = $this->get('router')->generate('bible_slider_verserange', array(
  2352.                         'translationUrl' => $translationUrl,
  2353.                         'bookUrl' => $planStepData['book']->getUrl(),
  2354.                         'chapterIndex' => $firstChapter->getOrdering(),
  2355.                         'verseStartIndex' => $firstVerse->getFullIndexDisplay(),
  2356.                         'verseEndIndex' => $lastVerse->getFullIndexDisplay()
  2357.                     ));                             
  2358.                 } else {
  2359.                     // Plan step contains text from more than one chapter
  2360.                     $planStepData['contents'] = $contents;
  2361.                     if($completeChapters) {
  2362.     /*                    $planStepData['range_name'] = $this->get('translator')->trans("bible.chapternav.bookchapterrange", array(
  2363.                             '%bookname%' => $planStepData['book']->getName(),
  2364.                             '%chapterstart%' => $firstChapter->getOrdering(),
  2365.                             '%chapterend%' => $lastChapter->getOrdering()
  2366.                         )); */
  2367.                         
  2368.                         $planStepData['slider_url'] = $this->get('router')->generate('bible_slider_chapter_range', array(
  2369.                             'translationUrl' => $translationUrl,
  2370.                             'bookUrl' => $planStepData['book']->getUrl(),
  2371.                             'chapterStartIndex' => $firstChapter->getOrdering(),
  2372.                             'chapterEndIndex' => $lastChapter->getOrdering()
  2373.                         ));
  2374.                     } else {
  2375.     /*                    $planStepData['range_name'] = $this->get('translator')->trans("bible.chapternav.bookchapterrangeverserange", array(
  2376.                             '%bookname%' => $planStepData['book']->getName(),
  2377.                             '%chapterstart%' => $firstChapter->getOrdering(),
  2378.                             '%chapterend%' => $lastChapter->getOrdering(),
  2379.                             '%versestart%' => $firstVerse->getFullIndexDisplay(),
  2380.                             '%verseend%' => $lastVerse->getFullIndexDisplay()
  2381.                         ));*/
  2382.                         
  2383.                         $planStepData['slider_url'] = $this->get('router')->generate('bible_slider_chapter_verse_range', array(
  2384.                             'translationUrl' => $translationUrl,
  2385.                             'bookUrl' => $planStepData['book']->getUrl(),
  2386.                             'chapterStartIndex' => $firstChapter->getOrdering(),
  2387.                             'chapterEndIndex' => $lastChapter->getOrdering(),
  2388.                             'verseStartIndex' => $firstVerse->getFullIndexDisplay(),
  2389.                             'verseEndIndex' => $lastVerse->getFullIndexDisplay()
  2390.                         ));
  2391.                     }                
  2392.                 }
  2393.                 
  2394.                 $planStepData['linktype_id'] = $this->LINK_TYPE_ID_BIBLE;            
  2395.                 $planStepData['text_style_override'] = $this->getTextStyleOverrideForBible($planStepData['book']->getId());
  2396.                 $planStepData['translation_url'] = $translationUrl;
  2397.                 $planStepData['show_bottom_nav'] = $bShowBottomNav;
  2398.                 
  2399.                 $planStepData['next_reading_plan_step'] = $this->getNextReadingPlanStep($readingPlanUrl$stepOrder$request);
  2400.                 $planStepData['prev_reading_plan_step'] = $this->getPreviousReadingPlanStep($readingPlanUrl$stepOrder);
  2401.                 
  2402.                 if($nUserID != '')
  2403.                     $planStepData['reading_plan_completed_info'] = $this->getUserStepInfo($readingPlanUrl$nUserID);
  2404.                 
  2405.                 $nCompletedStepOrder null;
  2406.                 if(isset($planStepData['reading_plan_completed_info']['completed_step_order']))
  2407.                     $nCompletedStepOrder $planStepData['reading_plan_completed_info']['completed_step_order'];
  2408.                 
  2409.                 $planStepData['completed_percentage'] = $this->getStepCompletedPercentage($readingPlanUrl$request);
  2410.                 // $planStepData['reading_plan_step_list'] = $this->getReadingPlanStepList($readingPlanUrl, $translationUrl);
  2411.                 
  2412.                 $planStepData['reading_plan_order_info'] = $this->getReadingPlanOrderInfo($readingPlanUrl);
  2413.                 $planStepData['reading_plan_url'] = $readingPlanUrl;
  2414.                 $planStepData['step_order'] = $stepOrder;
  2415.                 $planStepData['current_step_id'] = $readingPlanStep['id'];
  2416.                 $bPlanStarted = ($request->getSession()->get("reading_plan_started") == || $this->hasReadingPlanStarted($readingPlanUrl,$nUserID));
  2417.                 $planStepData['plan_started'] = $bPlanStarted;
  2418.                 
  2419.             /*    $bCompleted = false;
  2420.                 if($stepOrder <= $nCompletedStepOrder)
  2421.                     $bCompleted = true; */
  2422.                 
  2423.                 $nStepID $readingPlanStep['id'];                    
  2424.                 $bCompleted $this->IsReadingPlanStepCompleted($nStepID$request);        
  2425.                 $planStepData['step_completed'] = $bCompleted;
  2426.                 $bLastUncompleted false;
  2427.                 if(!$bCompleted)
  2428.                     $bLastUncompleted $this->IsLastReadingPlanStepUncompleted($nStepID$request);        
  2429.                     
  2430.                 $planStepData['last_step_uncompleted'] = $bLastUncompleted;
  2431.                 
  2432.                 $bLastStep $this->IsLastReadingPlanStep($nStepID$request);
  2433.                 $planStepData['is_last_step'] = $bLastStep;
  2434.                 
  2435.                 $planStepData['chapter_order'] = $firstChapter->getOrdering();
  2436.                 $chapterExplanations null;
  2437.               $nCChapterID null;
  2438.               $request->getSession()->set('current_explanation_cchapter_id''');
  2439.               $CChapter $firstChapter->getCanonicalization();
  2440.               if($CChapter != null)
  2441.               {
  2442.                   $nCChapterID $CChapter->getId();
  2443.                   $chapterExplanations $this->getChapterExplanation($nCChapterID$translationUrl$request); 
  2444.                             
  2445.                   $nExplainChapterTranslationID $this->getExplainChapterTranslation($nCChapterID$this->getCurrUserID($request), $translationUrl);        
  2446.                   if($nExplainChapterTranslationID > -1)
  2447.                   {
  2448.                       $planStepData['cchapter_id'] = $nCChapterID;  
  2449.                       $request->getSession()->set('current_explanation_cchapter_id'$nCChapterID); 
  2450.                       $request->getSession()->set('current_explanation_translation_id'$nExplainChapterTranslationID);          
  2451.                   }    
  2452.               }    
  2453.               
  2454.               $planStepData['chapter_explanation'] = $chapterExplanations;              
  2455.               if(!empty($chapterExplanations))
  2456.               {
  2457.                       $nTransID current($chapterExplanations)['translation_id'];
  2458.                       $explanation_translation $this->expositionData('Translation')->findOneById($nTransID);
  2459.                       
  2460.                       if($explanation_translation != null)
  2461.                       {
  2462.                           $passage $explanation_translation->getWork()->findFirstNonEmptyPassage($explanation_translation);
  2463.                           if($passage != null)
  2464.                           {    
  2465.                               $planStepData['explanation_text_style_override'] = $this->getTextStyleOverride($nTransID);
  2466.                               $planStepData['explanation_translation'] = $explanation_translation;
  2467.                               $planStepData['explanation_passage'] = $passage;
  2468.                               $planStepData['explanation_authors'] = $this->getAuthorInfo($request$nTransID);
  2469.                               $planStepData['explanation_text_to_speech'] = $this->getTextToSpeech($explanation_translation->getLanguage()->getId());
  2470.                               $planStepData['passage_ref'] = $this->getWorkPassageRefs($passage->getId(),$nTransID$request);
  2471.                               $planStepData['passage_multilink'] = $this->getWorkPassageMultiLink($passage->getId(),$nTransID$request);
  2472.                               $planStepData['explanation_col1_ref'] = $this->MULTI_URL_INDICATOR_BIBLE "_" $translationUrl "_" $canonicalBook->getUrl() . "_" $firstChapter->getOrdering();
  2473.                               $planStepData['explanation_col2_ref'] = $this->MULTI_URL_INDICATOR_EXPLANATION "_" $explanation_translation->getUrl();
  2474.                               
  2475.                               $nExplainChapterID $this->getExplainChapterID($nTransID$this->getCurrUserID($request));        
  2476.                               if(!empty($nExplainChapterID))
  2477.                               {
  2478.                                   $planStepData['explanation_cchapter_id'] = $nCChapterID;  
  2479.                                   $planStepData['explanation_translation_id'] = $nTransID;                         
  2480.                               }    
  2481.                           }
  2482.                       }    
  2483.               }
  2484.                                      
  2485.                 if($bSingleChapter)
  2486.                 {
  2487.                     $planStepData['bible_column_spec'] = $this->getBibleMultiColumnSpec($translationUrl$planStepData['book']->getUrl(), $canonicalStartChapterOrder$canonicalStartVerseOrder$canonicalEndVerseOrder);
  2488.                                               
  2489.                     return $this->createVersesView($planStepData$request);
  2490.                 }    
  2491.                 else
  2492.                 {
  2493.                     $planStepData['bible_column_spec'] = $this->getMultiColumnSpecForChapterRange($translationUrl$planStepData['book']->getUrl(), $canonicalStartChapterOrder$canonicalEndChapterOrder$canonicalStartVerseOrder$canonicalEndVerseOrder);
  2494.                                                
  2495.                     return $this->createChaptersView($planStepData$request);
  2496.                 }        
  2497.             }
  2498.         }
  2499.     }
  2500.     
  2501.     public function versealltranslationsAction($bookUrl$chapterIndex$verseIndexRequest $request$userSelected true)
  2502.     {
  2503.         $this->onloadPage($request);
  2504.         $nTranslationID $this->DEFAULT_BIBLE_TRANSLATION_ID;
  2505.            
  2506.         $nUserTranslationID $request->getSession()->get('current_bible_translation_id');
  2507.         if(!empty($nUserTranslationID))
  2508.         {
  2509.             $nTranslationID $nUserTranslationID;     
  2510.         }
  2511.         
  2512.         $aTransInfo $this->getAvailableTranslantion($bookUrl$nTranslationID);
  2513.         if(!empty($aTransInfo))
  2514.         {
  2515.             $nTranslationID $aTransInfo['id'];
  2516.             $translationUrl $aTransInfo['url'];
  2517.         }
  2518.        
  2519.         $verseData $this->getChapterPath($translationUrl$bookUrl$chapterIndex$request$userSelected);
  2520.         
  2521.         $verseData['verses'] = ($verseData['chapter'] === null) ? array() : $this->bibleData('Verse')->getByIndexRangeFromChapter(
  2522.             $verseIndex,
  2523.             $verseIndex,
  2524.             $verseData['chapter']
  2525.         );
  2526.            
  2527.         if(empty($verseData['verses']))
  2528.         {
  2529.             return $this->redirect($this->get('router')->generate('bible_chapter', array(
  2530.                     'translationUrl' => $translationUrl,                    
  2531.                     'bookUrl' => $bookUrl,                    
  2532.                     'chapterIndex' => $chapterIndex
  2533.                 )), 301);            
  2534.         } 
  2535.         
  2536.          if($verseIndex !== null) {
  2537.                 $verseData['verses_last_index'] = $verseIndex;
  2538.             }
  2539.         
  2540.         $verseData['verse'] = current($verseData['verses']);
  2541.         
  2542.         $verseData['all_translations'] = true;                 
  2543.         $verseData['content_class'] = 'verse_all_translations';
  2544.         $verseData['content_type'] = 'single_verse';
  2545.                                      
  2546.           $verseData['bible_column_spec'] = $this->getBibleMultiColumnSpec($translationUrl$bookUrl$chapterIndex$verseIndex);
  2547.    
  2548.            $nCurrVerseID current($verseData['verses'])->getId();
  2549.           $verseData['next_verse'] = $this->getNextVerse($nCurrVerseID);
  2550.           $verseData['prev_verse'] = $this->getPreviousVerse($nCurrVerseID);
  2551.           
  2552.           $verseData['book_url'] = $bookUrl;
  2553.           $verseData['chapter_index'] = $chapterIndex;
  2554.           $verseData['verse_index'] = $verseIndex;
  2555.                     
  2556.           $verseData['translation_url'] = $translationUrl;
  2557.           
  2558.           $verseData['slider_url'] = $this->get('router')->generate('bible_slider_verse', array(
  2559.                 'translationUrl' => $translationUrl,
  2560.                 'bookUrl' => $bookUrl,
  2561.                 'chapterIndex' => $chapterIndex,
  2562.                 'verseStartIndex' => $verseIndex
  2563.             ));
  2564.                   
  2565.         $versesView $this->createVersesAllTransView($verseData$nTranslationID$request);
  2566.         $this->setCurrentUrl($request);         
  2567.         return $versesView;
  2568.          
  2569.     }
  2570.     
  2571.     /**
  2572.      * Handles much of the code that is a verse with all translations views
  2573.      */
  2574.     protected function createVersesAllTransView($verseData$nTranslationID$request)
  2575.     {                 
  2576.           $this->checkIfOnMobile($request);  
  2577.           $aVerseInfo $this->getVerseInfo($verseData['verses']);
  2578.           
  2579.           $bInframe = (isset($verseData['in_frame']) && $verseData['in_frame']);
  2580.         $verseData['has_slider_item'] = $this->hasSliderItem($aVerseInfo$bInframe$request);
  2581.                     
  2582.         $aOTLE $this->getOTLERefForBible($aVerseInfo, ($verseData['content_class'] == 'chapter') ? array($verseData['chapter']) : array(), true);  
  2583.    //     $verseData['otle_ref'] = $aOTLE['otle_nonmusic'];   
  2584.         $verseData['otle_ref_music'] = $aOTLE['otle_music']; 
  2585.         
  2586.         $currVerse current($verseData['verses']);  
  2587.         
  2588.         $nBookId $verseData['book']->getCanonicalization()->getId();  
  2589.         $verseData['translations_by_language'] = $this->getBibleTranslationsByLanguageForVerses($nBookId$verseData['chapter_index'], $verseData['verse_index'], $verseData['chapter_index'], $verseData['verse_index']);
  2590.         
  2591.         $verseData['verse_content'] = $this->getAllBibleTranslationsForVerse($nBookId$verseData['chapter_index'], $verseData['verse_index']);
  2592.                
  2593.        // $verseData['verses_concept_all_trans'] = $this->getVerseContentWithConceptLinksForAllTrans($aVerseInfo['CVerseIDs']);
  2594.         
  2595.        if(!array_key_exists('canonical_chapter_start'$verseData)) {
  2596.             // Need to pass array($verseData['verses']) rather than just $verseData['verses'] so it will sort by ordering rather than by database ID
  2597.             $canonicalRangeData DataAssembly::getVerseNumberRange(DataAssembly::canonicalize(array($verseData['verses'])));
  2598.             if($canonicalRangeData !== null) {
  2599.                 if(array_key_exists('chapter_index'$verseData) && $verseData['chapter_index'] != null)
  2600.                 {
  2601.                     $verseData['canonical_chapter_start'] = $verseData['chapter_index'];
  2602.                     $verseData['canonical_chapter_end'] = null;
  2603.                     $verseData['canonical_verse_start'] = null;
  2604.                     $verseData['canonical_verse_end'] = null
  2605.                 }
  2606.                 else
  2607.                 {                    
  2608.                     $verseData['canonical_chapter_start'] = $canonicalRangeData['chapter_start'];
  2609.                     $verseData['canonical_chapter_end'] = $canonicalRangeData['chapter_end'];
  2610.                     $verseData['canonical_verse_start'] = $canonicalRangeData['verse_start'];
  2611.                     $verseData['canonical_verse_end'] = $canonicalRangeData['verse_end'];           
  2612.                 }
  2613.             }
  2614.         }
  2615.                                       
  2616. //        $verseData['book_list'] = $this->getBibleBookList($nTranslationID);
  2617.         
  2618.         // get qBible data
  2619.         $verseData['qbible_link'] = $this->getQBibleLink($verseData['book'], $verseData['chapter'], $verseData['verses']);
  2620.         
  2621.         // get commentary with file (pdf)
  2622.         $verseData['commentary_with_doc'] = $this->getCommentaryWithDocForBible($verseData['book'], current($verseData['verses'])->getChapter()->getOrdering());
  2623.         $verseData['text_style_override'] = $this->getTextStyleOverrideForBible($verseData['book']->getId());
  2624.     //    $verseData['text_to_speech'] = $this->getTextToSpeech($nLanguageID);
  2625.         
  2626.  /*       if($verseData['content_type'] == 'single_verse')
  2627.         {
  2628.             $stories = DataAssembly::findVerseStories($verseData['verses'], $this->getManager(), true);
  2629.             if(!empty($stories)) {
  2630.                 $illustrations = array();
  2631.                 $explanations = array();
  2632.                 foreach($stories as $story) {
  2633.                     $illustrations = array_merge($illustrations, $story->getIllustrations()->toArray());
  2634.                     $explanations = array_merge($explanations, $story->getExplanations()->toArray());
  2635.                 }
  2636.                 $verseData['verse_illustrations'] = $illustrations;
  2637.                                           
  2638.                 if(count($explanations) > 0 && $explanations[0]->selectTranslation() != null && $explanations[0]->findFirstPassage() != null)
  2639.                 {
  2640.                     $verseData['verse_explanations'] = $explanations;
  2641.                     $trans = $explanations[0]->selectTranslation();                
  2642.                     $verseData['passage_multilink'] = $this->getWorkPassageMultiLink($explanations[0]->findFirstPassage()->getId(),$trans->getId(), $request);
  2643.                     $verseData['authors'] = $this->getAuthorInfo($request, $trans->getId());
  2644.                 }    
  2645.             }
  2646.         } */
  2647.     
  2648.         return $this->renderView('versealltrans'$verseData);
  2649.     }    
  2650.     
  2651.      /**
  2652.      * Show book list on a popup
  2653.      */
  2654.     public function selectbookAction($translationUrl$translationUrl2$translationUrl3Request $request)
  2655.     {    
  2656.       $nTranslationID $this->getBibleTranslationID($translationUrl);     
  2657.       if($translationUrl == '-none-' || empty($nTranslationID))
  2658.       {
  2659.            $translation $this->getFirstBibleTranslation($request);
  2660.            $translationUrl $translation['url'];
  2661.            $nTranslationID $translation['id'];
  2662.            $data['translation_name'] = $translation['name'];
  2663.       }
  2664.            
  2665.       $data['translation_url'] = $translationUrl;
  2666.  /*     if($bookUrl == '-none-')
  2667.           $bookUrl = $this->DEFAULT_BIBLE_VERSION;
  2668.       
  2669.       $data['book_url'] = $bookUrl;   */
  2670.       
  2671.     //  echo 'tid:'.$nTranslationID;
  2672.       if(empty($nTranslationID))
  2673.           $nTranslationID $this->DEFAULT_BIBLE_TRANSLATION_ID;
  2674.     
  2675.       $nTranslationID2 null;
  2676.       $nTranslationID3 null;
  2677.       if(!empty($translationUrl2) && $translationUrl2 != "-none-")
  2678.       {                 
  2679.           $nTranslationID2 $this->getBibleTranslationID($translationUrl2);
  2680.       }
  2681.       
  2682.       if(!empty($translationUrl3) && $translationUrl3 != "-none-")
  2683.       {                 
  2684.           $nTranslationID3 $this->getBibleTranslationID($translationUrl3);
  2685.       }
  2686.       
  2687.       $data['book_list'] = $this->getBibleBookList($request$nTranslationID$nTranslationID2$nTranslationID3);
  2688.       
  2689.       return $this->renderView('selectbook'$data);
  2690.     }
  2691.     
  2692.     /**
  2693.      * Show chapter list on a popup
  2694.      */
  2695.     public function selectchapterAction($translationUrl$translationUrl2$translationUrl3$bookUrlRequest $request$inFrame false )
  2696.     {         
  2697.       $data['translation_url'] = $translationUrl;
  2698.       $data['book_url'] = $bookUrl;   
  2699.       $data['in_frame'] = $inFrame;
  2700.       
  2701.       if(empty($translationUrl))
  2702.           $translationUrl $this->DEFAULT_BIBLE_VERSION;
  2703.           
  2704.       $aTrans $this->getBibleTransInfo($translationUrl);    
  2705.       $data['translation_name'] = $aTrans['name'];
  2706.              
  2707.       $data['chapter_list'] = $this->getBibleChapterList($translationUrl$translationUrl2$translationUrl3$bookUrl);
  2708.       
  2709.       $data['book_summary_url'] = $this->getBibleBookSummary($translationUrl$bookUrl);
  2710.                        
  2711.       return $this->renderView('selectchapter'$data);
  2712.     }
  2713.     
  2714.     /**
  2715.      * Show translation list on a popup
  2716.      */
  2717.     public function selecttranslationAction(Request $request)
  2718.     {    
  2719.       $data = array();         
  2720.       return $this->renderView('selecttranslation'$data);
  2721.     } 
  2722.     
  2723.     /**
  2724.      * Show translation list on a popup with translation data
  2725.      */
  2726.     public function selecttranslationfrombookAction(Request $request)
  2727.     {                          
  2728.       $data['translation_list'] = $this->getBibleTranslationsByLanguage();  
  2729.       return $this->renderView('selecttranslationfrombook'$data);
  2730.     }     
  2731.     
  2732.     public function biblenewAction($translationUrl$bookUrlRequest $request$chapterIndex 1)
  2733.     {        
  2734.         if($this->getCurrUserID($request) == '')
  2735.         {
  2736.             return $this->redirect($this->get('router')->generate('login', array()), 301);
  2737.         } 
  2738.         else
  2739.         {
  2740.             $this->onloadPage($request);
  2741.             $aBookInfo $this->getBibleTranslationInfo($translationUrl$bookUrl);
  2742.             if(empty($aBookInfo))
  2743.             {
  2744.                 $response = new Response();
  2745.                 $response->setStatusCode(404);
  2746.                 return $this->renderView('no_content', array(), $response);
  2747.             }
  2748.             else
  2749.             {
  2750.                 $data['translation_url'] = $translationUrl;
  2751.                   $data['book_url'] = $bookUrl;   
  2752.                 $data['chapter_index'] = $chapterIndex;            
  2753.                 $data['book_name'] = $aBookInfo['book_name']; 
  2754.                 $data['translation_name'] = $aBookInfo['name']; 
  2755.                 $data['bible_new'] = true;
  2756.             }
  2757.              
  2758.             $this->setCurrentUrl($request);                            
  2759.               return $this->renderView('biblenew'$data);
  2760.           }
  2761.     }   
  2762.     
  2763.     // The middle frame for chapters
  2764.     public function bibleframeexplanationchapterAction($translationUrl$bookUrl$chapterIndexRequest $request)
  2765.     {        
  2766.         $this->onloadPage($request);
  2767.         $bInframe true;
  2768.         $aVerseInfo $this->getVerseInfoForFrame($translationUrl$bookUrl$chapterIndex);
  2769.                 
  2770.         $data['referring_passages'] = $this->getBibleCrossRef($aVerseInfotruefalse);
  2771.      //   $data['core_passages'] = $this->getBibleRefPassage($aVerseInfo, false, true); 
  2772.         $bookInfo $this->getBibleBookInfo($translationUrl$bookUrl);        
  2773.         $data['book_name'] = $bookInfo['name'];   
  2774.         $data['chapter_index'] = $chapterIndex;                                       
  2775.         $data['bFullChapter'] = true;   
  2776.         $data['in_frame'] = $bInframe;
  2777.               
  2778.           return $this->renderView('biblerefinframe'$data);
  2779.     }
  2780.     
  2781.     // The middle frame for verses
  2782.     public function bibleframeexplanationverseAction($translationUrl$bookUrl$chapterIndex$verseIndexRequest $request)
  2783.     {        
  2784.         $this->onloadPage($request);
  2785.         $bInframe true;
  2786.         $aVerseInfo $this->getVerseInfoForFrame($translationUrl$bookUrl$chapterIndex$verseIndex);
  2787.         
  2788.         $data['referring_passages'] = $this->getBibleCrossRef($aVerseInfofalsefalse);
  2789.     //    $data['core_passages'] = $this->getBibleRefPassage($aVerseInfo, false, true);   
  2790.         $bookInfo $this->getBibleBookInfo($translationUrl$bookUrl);        
  2791.         $data['book_name'] = $bookInfo['name'];
  2792.         $data['chapter_index'] = $chapterIndex
  2793.         $data['verse_index'] = $verseIndex;
  2794.         $data['in_frame'] = true;
  2795.         
  2796.         $data['translation_url'] = $translationUrl;
  2797.         $data['book_url'] = $bookUrl;
  2798.         
  2799.           return $this->renderView('biblerefinframe'$data);
  2800.     }
  2801.     
  2802.      /**
  2803.      * Show slider contents
  2804.      */
  2805.     public function bibleSliderAction($translationUrl$bookUrl$chapterIndexRequest $request$verseStartIndex null$verseEndIndex null$userSelected true)
  2806.     {    
  2807.         $data $this->getChapterPath($translationUrl$bookUrl$chapterIndex$request$userSelected);
  2808.        // print_r($data);
  2809.         if($verseStartIndex == null)
  2810.         {
  2811.             $data['verses'] = $this->bibleData('Verse')->getByChapter($data['chapter']);
  2812.             $data['content_type'] = 'verseRange';
  2813.         }
  2814.         else
  2815.         {
  2816.             $data['verses'] = ($data['chapter'] === null) ? array() : $this->bibleData('Verse')->getByIndexRangeFromChapter(
  2817.                 $verseStartIndex,
  2818.                 $verseEndIndex,
  2819.                 $data['chapter']
  2820.             );
  2821.             
  2822.             if($verseEndIndex == null)
  2823.                 $data['content_type'] = 'single_verse';
  2824.             else
  2825.                 $data['content_type'] = 'verseRange';
  2826.         }
  2827.         if($verseEndIndex !== null) {
  2828.             $data['verses_last_index'] = $verseEndIndex;
  2829.         }
  2830.         
  2831.         $nInFrame $request->query->get('if');
  2832.         $data['in_frame'] = ($nInFrame == 1);
  2833.         
  2834.         $chapter $data['chapter'];
  2835.         if($chapter == null)
  2836.         {
  2837.             $data['content_class'] = 'verse';
  2838.         }
  2839.         else
  2840.         {                        
  2841.             $chapterVerses $data['chapter']->getVerses();            
  2842.             
  2843.             if($verseStartIndex == null || ($verseStartIndex != null && $verseStartIndex == $chapterVerses->first()->getOrdering() && $verseEndIndex == $chapterVerses->last()->getOrdering()) )
  2844.             {
  2845.                 $data['content_class'] = 'chapter';
  2846.             } 
  2847.             else 
  2848.             {
  2849.                 $data['content_class'] = 'verse';                
  2850.             }            
  2851.         }
  2852.                 
  2853.         $data['translation_url'] = $translationUrl;
  2854.                               
  2855.         $data['bible_column_spec'] = $this->getBibleMultiColumnSpec($translationUrl$bookUrl$chapterIndex$verseStartIndex$verseEndIndex);
  2856.             
  2857.         $chapterExplanations null;
  2858.           $nCChapterID null;
  2859.           $request->getSession()->set('current_explanation_cchapter_id''');
  2860.           $CChapter $data['chapter']->getCanonicalization();
  2861.           if($CChapter != null)
  2862.           {
  2863.               $nCChapterID $CChapter->getId();
  2864.               $chapterExplanations $this->getChapterExplanation($nCChapterID$translationUrl$requesttrue); 
  2865.                         
  2866.               $nExplainChapterTranslationID $this->getExplainChapterTranslation($nCChapterID$this->getCurrUserID($request), $translationUrl);        
  2867.               if($nExplainChapterTranslationID > -1)
  2868.               {
  2869.                   $data['cchapter_id'] = $nCChapterID;  
  2870.                   $request->getSession()->set('current_explanation_cchapter_id'$nCChapterID); 
  2871.                   $request->getSession()->set('current_explanation_translation_id'$nExplainChapterTranslationID);          
  2872.               }    
  2873.           }    
  2874.           
  2875.           $data['chapter_explanation'] = $chapterExplanations;
  2876.           $data['chapter_order'] = $chapterIndex;
  2877.           $data['book_url'] = $bookUrl;      
  2878.           if(!empty($chapterExplanations))
  2879.           {
  2880.                   $nTransID current($chapterExplanations)['translation_id'];
  2881.                   $bIsModern current($chapterExplanations)['is_modern'];
  2882.                   $explanation_translation $this->expositionData('Translation')->findOneById($nTransID);
  2883.                   
  2884.                   if($explanation_translation != null)
  2885.                   {
  2886.                       $passage $explanation_translation->getWork()->findFirstNonEmptyPassage($explanation_translation);
  2887.                       if($passage != null)
  2888.                       {    
  2889.                           $data['is_modern_chapter_summary'] = $bIsModern;
  2890.                           $data['explanation_text_style_override'] = $this->getTextStyleOverride($nTransID);
  2891.                           $data['explanation_translation'] = $explanation_translation;
  2892.                           $data['explanation_passage'] = $passage;
  2893.                           $data['explanation_authors'] = $this->getAuthorInfo($request$nTransID);
  2894.                           $data['explanation_text_to_speech'] = $this->getTextToSpeech($explanation_translation->getLanguage()->getId());
  2895.                           $data['passage_ref'] = $this->getWorkPassageRefs($passage->getId(),$nTransID$request);
  2896.                           $data['passage_multilink'] = $this->getWorkPassageMultiLink($passage->getId(),$nTransID$request);
  2897.                           $data['explanation_col1_ref'] = $this->MULTI_URL_INDICATOR_BIBLE "_" $translationUrl "_" $bookUrl "_" $chapterIndex;
  2898.                           $data['explanation_col2_ref'] = $this->MULTI_URL_INDICATOR_EXPLANATION "_" $explanation_translation->getUrl();
  2899.                           
  2900.                           $nExplainChapterID $this->getExplainChapterID($nTransID$this->getCurrUserID($request));        
  2901.                           if(!empty($nExplainChapterID))
  2902.                           {
  2903.                               $data['explanation_cchapter_id'] = $nCChapterID;  
  2904.                               $data['explanation_translation_id'] = $nTransID;                         
  2905.                           }    
  2906.                       }
  2907.                   }    
  2908.           }
  2909.                 
  2910.         return $this->createSliderView($data$request);
  2911.     }
  2912.     
  2913.     /**
  2914.      * Create slider view
  2915.      */
  2916.     protected function createSliderView($data$request)
  2917.     {                          
  2918.           $this->checkIfOnMobile($request);  
  2919.           $aVerseInfo $this->getVerseInfo($data['verses']);
  2920.           
  2921.           if(!isset($data['in_frame']) || !$data['in_frame'])
  2922.           {
  2923.               // Show chapter level refs for verse pages too.
  2924.           //    $bChapter = ($data['content_class'] == 'chapter');
  2925.               $bChapter true;
  2926.             $data['referring_passages'] = $this->getBibleRefPassageNew($aVerseInfo$bChapterfalse);        
  2927.             $data['core_passages'] = $this->getBibleRefPassageNew($aVerseInfo$bChaptertrue);
  2928.         }
  2929.        
  2930.         $data['explanation_ref'] = $this->getExplanationRefForBible($aVerseInfo$request);
  2931.         
  2932.         $data['gced_ref'] = $this->getGCEDRefForBible($aVerseInfo, ($data['content_class'] == 'chapter') ? array($data['chapter']) : array()); 
  2933.                 
  2934.         $aOTLE $this->getOTLERefForBible($aVerseInfo, ($data['content_class'] == 'chapter') ? array($data['chapter']) : array());         
  2935.         $data['otle_ref'] = $aOTLE['otle_nonmusic'];   
  2936.         $data['otle_ref_music'] = $aOTLE['otle_music'];
  2937.                
  2938.         $data['verse_cross'] = $this->getVerseCrossRefs($aVerseInfo$request);
  2939.         $data['word_explanations'] = $this->getBibleWordExplanations($aVerseInfo$request);
  2940.               
  2941.           $data['verse_story'] = $this->getStoriesForVerses($aVerseInfo$request);
  2942.            
  2943.         $data['explained_verse'] = $this->getFirstExplainedVerse($aVerseInfo$request);
  2944.                                 
  2945.         $bible_column_spec '';
  2946.         if(array_key_exists('bible_column_spec'$data))
  2947.             $bible_column_spec $data['bible_column_spec'];    
  2948.              
  2949.         $translation $data['book']->getTranslation();
  2950.         $nTranslationID $translation->getId();
  2951.         $nLanguageID $translation->getLanguage()->getId();
  2952.         
  2953.         $data['book_url'] = $data['book']->getUrl();
  2954.         $data['chapter_index'] = $aVerseInfo['FirstChapterIndex'];
  2955.                   
  2956.         // get qBible data
  2957.         $data['qbible_link'] = $this->getQBibleLink($data['book'], $data['chapter'], $data['verses']);
  2958.         
  2959.         // get commentary with file (pdf)
  2960.         $data['commentary_with_doc'] = $this->getCommentaryWithDocForBible($data['book'], current($data['verses'])->getChapter()->getOrdering());
  2961.                 
  2962.   /*      if($data['content_type'] == 'single_verse')
  2963.         {    
  2964.               $nSelectedExplTransID = $request->query->get('et');
  2965.             $stories = DataAssembly::findVerseStories($data['verse'], $this->getManager(), true);
  2966.             if(!empty($stories)) {
  2967.                 $illustrations = array();
  2968.                 $explanations = array();
  2969.                 foreach($stories as $story) {
  2970.                     $illustrations = array_merge($illustrations, $story->getIllustrations()->toArray());
  2971.                     $explanations = array_merge($explanations, $story->getExplanations()->toArray());
  2972.                 }
  2973.                 $data['verse_illustrations'] = $illustrations;                                      
  2974.                 if(count($explanations) > 0 && $explanations[0]->selectTranslation() != null && $explanations[0]->findFirstPassage() != null)
  2975.                 {               
  2976.                 // get the explanation with the same language of the verse if there is
  2977.                     $data['verse_explanations'] = $explanations;
  2978.                                         
  2979.                     $verseexplanation = $this->getVerseExplanationInText($request, $explanations, $nLanguageID);
  2980.                     if(!empty($verseexplanation))
  2981.                     {
  2982.                         $data['verse_explanations_for_combo'] = $this->getVerseExplanationsForVerse($data['verse']->getId());
  2983.                     
  2984.                         $data['verse_explanation'] = $verseexplanation;                        
  2985.                         $data['passage_multilink'] = $this->getWorkPassageMultiLink($verseexplanation->findFirstNonEmptyPassage()->getId(),$verseexplanation->getId(), $request);
  2986.                         $data['authors'] = $this->getAuthorInfo($request, $verseexplanation->getId());
  2987.                     }                     
  2988.                 }    
  2989.             }
  2990.         }    */
  2991.         return $this->renderView('refsidr'$data);
  2992.     }   
  2993.     
  2994.     public function bibleChapterRangeSliderAction($translationUrl$bookUrl$chapterStartIndex$chapterEndIndexRequest $request$verseStartIndex null$verseEndIndex null$userSelected true)
  2995.     {            
  2996.         $chapterRangeData = array(
  2997.             'book' => $this->getBookByUrl($translationUrl$bookUrl$request$userSelected)       
  2998.         );
  2999.         if($verseStartIndex === null) {
  3000.             $chapterRangeData['content_class'] = 'chapter';            
  3001.         } else {
  3002.             $chapterRangeData['content_class'] = 'verse';
  3003.         }
  3004.      
  3005.         $chapterRangeData['contents'] = DataAssembly::getVerseRangeFromBook($chapterRangeData['book'], $chapterStartIndex$chapterEndIndex$verseStartIndex$verseEndIndex);
  3006.         $chapterRangeData['translation_url'] = $translationUrl;
  3007.        
  3008.         $chapterRangeData['bible_column_spec'] = $this->getMultiColumnSpecForChapterRange($translationUrl$bookUrl$chapterStartIndex$chapterEndIndex$verseStartIndex$verseEndIndex);
  3009.         
  3010.         return $this->createChaptersSliderView($chapterRangeData$request);
  3011.     }
  3012.     
  3013.     protected function createChaptersSliderView($chapterRangeData$request)
  3014.     {            
  3015.         $allVerses array_reduce($chapterRangeData['contents'], 'array_merge', array());
  3016.         $aVerseInfo $this->getVerseInfo($allVerses);
  3017.         if($chapterRangeData['content_class'] !== 'storytext') {          
  3018.          // $chapterRangeData['verse_story'] = $this->getStoriesForVerses($aVerseInfo, $request);
  3019.         }
  3020. //     echo 'aaa';   
  3021.         $bChapter false;                
  3022.         $chapterRangeData['referring_passages'] = $this->getBibleRefPassageNew($aVerseInfo$bChapterfalse);
  3023.         $chapterRangeData['core_passages'] = $this->getBibleRefPassageNew($aVerseInfo$bChaptertrue);
  3024.         $chapterRangeData['explanation_ref'] = $this->getExplanationRefForBible($aVerseInfo$request);
  3025.         $chapterRangeData['gced_ref'] = $this->getGCEDRefForBible($aVerseInfo, array());   
  3026.         $aOTLE $this->getOTLERefForBible($aVerseInfo, array());  
  3027.         $chapterRangeData['otle_ref'] = $aOTLE['otle_nonmusic'];   
  3028.         $chapterRangeData['otle_ref_music'] = $aOTLE['otle_music']; 
  3029.         $chapterRangeData['verse_cross'] = $this->getVerseCrossRefs($aVerseInfo$request);
  3030.         $chapterRangeData['word_explanations'] = $this->getBibleWordExplanations($aVerseInfo$request);
  3031.         $chapterRangeData['explained_verse'] = $this->getFirstExplainedVerse($aVerseInfo$request);
  3032.          
  3033.         $locale $request->getLocale();
  3034.           $nUILanguageID $this->getLanguageIDByShortCode($locale);  
  3035.         $chapterRangeData['translations_by_language'] = $this->getBibleTranslationsByLanguageForVerses($chapterRangeData['book']->getCanonicalization()->getId(), current($allVerses)->getChapter()->getOrdering(), current($allVerses)->getIndexDisplay(), end($allVerses)->getChapter()->getOrdering(), end($allVerses)->getIndexDisplay(), $nUILanguageID);
  3036.                           
  3037.         $chapterRangeData['verses_concept'] = $this->getVerseContentWithConceptLinks($request$allVerses$chapterRangeData['bible_column_spec']);
  3038.         
  3039.         $chapterRangeData['book_url'] = $chapterRangeData['book']->getUrl();
  3040.         $chapterRangeData['chapter_index'] = $aVerseInfo['FirstChapterIndex'];
  3041.         return $this->renderView('refsidr'$chapterRangeData);
  3042.     }
  3043.     
  3044.     public function selectbiblestoryAction(Request $request)
  3045.     {       
  3046.       $locale $request->getLocale();  
  3047.       $sSearchText $request->query->get('st');
  3048.       if(empty($sSearchText))                 
  3049.           $data['stories'] = $this->getExplainedStoryList($locale); 
  3050.       else
  3051.           $data['stories'] = $this->getExplainedStoryListForSearch($locale$sSearchText); 
  3052.               
  3053.       return $this->renderView('selectbiblestory'$data);
  3054.     } 
  3055.     
  3056.     /**
  3057.      * load chapter summary after loading the main chpater page
  3058.      */
  3059.     public function chaptersummaryAction($translationUrl$bookUrl$chapterIndex$summaryTranslationIDRequest $request)
  3060.     {        
  3061.       $response null;
  3062.             
  3063.         $data['chapter_order'] = $chapterIndex;      
  3064.     //  $data['translation_url'] = $translationUrl;                 
  3065.     //  $data['book_url'] = $bookUrl;      
  3066.       if(!empty($summaryTranslationID))
  3067.       {
  3068.               $nTransID $summaryTranslationID;                  
  3069.               $explanation_translation $this->expositionData('Translation')->findOneById($nTransID);
  3070.               
  3071.               if($explanation_translation != null)
  3072.               {
  3073.                   $passage $explanation_translation->getWork()->findFirstNonEmptyPassage($explanation_translation);
  3074.                   if($passage != null)
  3075.                   {                          
  3076.                       $data['explanation_text_style_override'] = $this->getTextStyleOverride($nTransID);
  3077.                       $data['explanation_translation'] = $explanation_translation;
  3078.                       $data['explanation_passage'] = $passage;
  3079.                       $data['explanation_authors'] = $this->getAuthorInfo($request$nTransID);
  3080.                       $data['explanation_text_to_speech'] = $this->getTextToSpeech($explanation_translation->getLanguage()->getId());
  3081.                       $data['passage_ref'] = $this->getWorkPassageRefs($passage->getId(),$nTransID$request);
  3082.                       $data['passage_multilink'] = $this->getWorkPassageMultiLink($passage->getId(),$nTransID$request);
  3083.                       $data['explanation_col1_ref'] = $this->MULTI_URL_INDICATOR_BIBLE "_" $translationUrl "_" $bookUrl "_" $chapterIndex;
  3084.                       $data['explanation_col2_ref'] = $this->MULTI_URL_INDICATOR_EXPLANATION "_" $explanation_translation->getUrl();
  3085.                       
  3086.                       $nExplainChapterID $this->getExplainChapterID($nTransID$this->getCurrUserID($request));        
  3087.                       if(!empty($nExplainChapterID))
  3088.                       {
  3089.                           $nCChapterID $this->getCChapterID($bookUrl$chapterIndex);
  3090.                           $data['explanation_cchapter_id'] = $nCChapterID;  
  3091.                           $data['explanation_translation_id'] = $nTransID;                         
  3092.                       }                      
  3093.                   }
  3094.               }    
  3095.       }
  3096.       
  3097.       // Set this b/c footnote popup issue
  3098.       $data['bible_chapter_summary'] = true;
  3099.       
  3100.       return $this->renderView('chaptersummaryintext'$data$response);
  3101.     }
  3102.     
  3103.     /**
  3104.      * Show translation list on a popup
  3105.      */
  3106.     public function selectcompareAction($translationUrl$translationUrl2$bookUrl$cbookID$chapterStartOrder$chapterEndOrder$verseStartOrder$verseEndOrderRequest $request)
  3107.     {         
  3108.       $data['translation_url'] = $translationUrl;
  3109.       $data['translation_url2'] = $translationUrl2;      
  3110.       $data['book_url'] = $bookUrl;   
  3111.             
  3112.       if(empty($translationUrl))
  3113.           $translationUrl $this->DEFAULT_BIBLE_VERSION;
  3114.           
  3115.      // $aTrans = $this->getBibleTransInfo($translationUrl);    
  3116.      // $data['translation_name'] = $aTrans['name'];
  3117.       
  3118.       $data['single_verse'] = ($chapterStartOrder == $chapterEndOrder && $verseStartOrder == $verseEndOrder);
  3119.       
  3120.       $locale $request->getLocale();
  3121.       $nUILanguageID $this->getLanguageIDByShortCode($locale);       
  3122.       $data['translations_by_language'] = $this->getBibleTranslationsByLanguageForVerses($cbookID$chapterStartOrder$verseStartOrder$chapterEndOrder$verseEndOrder$nUILanguageID);    
  3123.       
  3124.       if($chapterEndOrder == $chapterStartOrder)
  3125.           $chapterEndOrder null;
  3126.           
  3127.       if($verseEndOrder == $verseStartOrder)
  3128.           $verseEndOrder null;  
  3129.           
  3130.       $data['chapter_start_order'] = $chapterStartOrder;
  3131.       $data['chapter_end_order'] = $chapterEndOrder;
  3132.       $data['verse_start_order'] = $verseStartOrder;
  3133.       $data['verse_end_order'] = $verseEndOrder;    
  3134.                              
  3135.       return $this->renderView('selectcompare'$data);
  3136.     }
  3137.     
  3138.     public function selectstorytranslationAction(Request $request)
  3139.     {       
  3140.       $locale $request->getLocale();   
  3141.       $data['story_url'] = $request->query->get('storyurl');
  3142.       $data['bible_translation_url'] = $request->query->get('bturl');
  3143.       $data['commentary_url'] = $request->query->get('commentaryurl');
  3144.       $nCBookID $request->query->get('cbookid');
  3145.       $nChapterStartOrder $request->query->get('chapterstartorder');
  3146.       $nVerseStartIndex $request->query->get('versestartindex');
  3147.       $nChapterEndOrder $request->query->get('chapterendorder');
  3148.       $nVerseEndIndex $request->query->get('verseendindex');
  3149.       
  3150.       $locale $request->getLocale();
  3151.       $nUILanguageID $this->getLanguageIDByShortCode($locale);   
  3152.       $data['translations_by_language'] = $this->getBibleTranslationsByLanguageForVerses($nCBookID$nChapterStartOrder$nVerseStartIndex$nChapterEndOrder$nVerseEndIndex$nUILanguageID); 
  3153.                    
  3154.       return $this->renderView('selectstorytranslation'$data);
  3155.     } 
  3156.     
  3157.     /**
  3158.      * Show translation list on a popup
  3159.      */
  3160.     public function selecttranslationindexAction(Request $request$translationUrl)
  3161.     {               
  3162.       $locale $request->getLocale();
  3163.       $nLanguageID $this->getLanguageIDByShortCode($locale);           
  3164.    //   $nLanguageID = $this->getLanguageIDByBibleTrans($translationUrl);
  3165.       $data['translation_list'] = $this->getBibleTranslationListByLanguage($nLanguageID);  
  3166.       $data['translation_url'] = $translationUrl;               
  3167.       return $this->renderView('selecttranslationindex'$data);
  3168.     } 
  3169.     
  3170.     /**
  3171.      * Show book list on a popup for advanced search
  3172.      */
  3173.     public function selectbiblebooksforsearchAction(Request $request)
  3174.     {    
  3175.       $nTranslationID $request->query->get('trans');    
  3176.   //    $nLanguageID = $request->query->get('lang'); 
  3177.       $sSelectedBookIDs $request->query->get('selectedids');
  3178.     
  3179.       $data['book_list'] = $this->getBibleBookList($request$nTranslationID);
  3180.       $data['selected_ids'] = $sSelectedBookIDs;
  3181.       
  3182.       return $this->renderView('selectbiblebooksforsearch'$data);
  3183.     }
  3184.     
  3185.     // For reading plan - work
  3186.     protected function readingplanStepForWork($translationUrl$work_id$passageId$readingPlanUrl$planstep$request)
  3187.     {     
  3188.         $translation $this->expositionData('Translation')->findOneBy(array('url' => $translationUrl'isPublic' => true));
  3189.          if($translation == null) {
  3190.             $response = new Response();
  3191.             $response->setStatusCode(404);
  3192.             return $this->renderView('no_content', array(), $response);
  3193.         }
  3194.         if($passageId != "")
  3195.         {
  3196.             $request->getSession()->set("current_reading_plan_work_id"$work_id);
  3197.             $request->getSession()->set("current_reading_plan_work_translation_url"$translationUrl);
  3198.         }
  3199.         
  3200.         $passage = ($passageId !== null)
  3201.             ? $this->expositionData('Passage')->findOneById($passageId)
  3202.             : (($translation !== null) ? $translation->getWork()->findFirstNonEmptyPassage($translation) : null);
  3203.     
  3204.         $this->checkIfOnMobile($request);
  3205.         $locale $request->getLocale();
  3206.         $sUrlCompareTo $request->query->get('compareTo');
  3207.         $aCompare explode(";;"$sUrlCompareTo);
  3208.         $nCompareLen count($aCompare);
  3209.         $compareTo null;
  3210.         $compareTo2 null;    
  3211.         $text_to_speech2 null;
  3212.         $text_to_speech3 null;
  3213.         $text_style_override_compare_to null;   
  3214.         $text_style_override_compare_to2 null
  3215.         $translation_shortname2 null;
  3216.         $translation_shortname3 null;
  3217.         if($nCompareLen && $aCompare[0] != '')
  3218.         {
  3219.             $compareTo $this->expositionData('Translation')->findOneBy(array('url' => $aCompare[0], 'isPublic' => true));   
  3220.             if($compareTo != null)    
  3221.             {
  3222.                 $nLanguageID2 $compareTo->getLanguage()->getId();
  3223.                 $text_style_override_compare_to $this->getTextStyleOverride($nLanguageID2);
  3224.                 $text_to_speech2 $this->getTextToSpeech($nLanguageID2);
  3225.                 
  3226.                 $translation_shortname2 $this->getWorkTranslationShortName($compareTo->getId());                
  3227.             }    
  3228.         }         
  3229.         
  3230.         if($nCompareLen == && $aCompare[1] != ''
  3231.         {           
  3232.             $compareTo2 $this->expositionData('Translation')->findOneBy(array('url' => $aCompare[1], 'isPublic' => true)); 
  3233.             if($compareTo2 != null)    
  3234.             {
  3235.                 $nLanguageID3 $compareTo2->getLanguage()->getId();
  3236.                 $text_style_override_compare_to2 $this->getTextStyleOverride($nLanguageID3);
  3237.                 $text_to_speech3 $this->getTextToSpeech($nLanguageID3);
  3238.                 $translation_shortname3 $this->getWorkTranslationShortName($compareTo2->getId());
  3239.             }    
  3240.         }    
  3241.             
  3242.         $chapterExplanations $this->getChapterExplanationsForText($translation); 
  3243.         $chapterExplanationsForCombo $this->getChapterExplanationsForTextForCombo($translation); 
  3244.         $ref_column_spec '';
  3245.         
  3246.         $bSwedenborg $this->isSwedenborg($translation->getId());
  3247.         if($bSwedenborg)
  3248.             $ref_column_spec $this->MULTI_URL_INDICATOR_SWEDENBORG_WORK;    
  3249.         else
  3250.             $ref_column_spec $this->MULTI_URL_INDICATOR_EXPLANATION;    
  3251.         
  3252.         $ref_column_spec .= '_' $translation->getUrl();
  3253.         if($passage != null && $bSwedenborg)
  3254.             $ref_column_spec .= '_' $passage->getSwedenborgSection();
  3255.             
  3256.         $nPassageID null;    
  3257.         if($passage != null)
  3258.             $nPassageID $passage->getId();
  3259.             
  3260.         $nLanguageID $translation->getLanguage()->getId();      
  3261.         $data = array(
  3262.             'translation' => $translation,
  3263.             'passage' => $passage,
  3264.             'compare_to' => $compareTo,
  3265.             'compare_to2' => $compareTo2,
  3266.             'nav_mode' => 'translation',            
  3267.             'chapter_explanations' => $chapterExplanations,
  3268.             'chapter_explanations_for_combo' => $chapterExplanationsForCombo,
  3269.             'ref_column_spec' => $ref_column_spec,
  3270.             'text_style_override' => $this->getTextStyleOverride($nLanguageID),
  3271.             'text_style_override_compare_to' => $text_style_override_compare_to,
  3272.             'text_style_override_compare_to2' => $text_style_override_compare_to2,
  3273.             'text_to_speech1' => $this->getTextToSpeech($nLanguageID),
  3274.             'text_to_speech2' => $text_to_speech2,
  3275.             'text_to_speech3' => $text_to_speech3,            
  3276.             'translation_shortname2' => $translation_shortname2,
  3277.             'translation_shortname3' => $translation_shortname3,
  3278.             'plan_step' => $planstep        
  3279.         );
  3280.         
  3281.         $stepOrder $planstep['step_order'];        
  3282.         $data['next_reading_plan_step'] = $this->getNextReadingPlanStep($readingPlanUrl$stepOrder$request);
  3283.         $data['prev_reading_plan_step'] = $this->getPreviousReadingPlanStep($readingPlanUrl$stepOrder);
  3284.         
  3285.         $nUserID $request->getSession()->get("user_id");
  3286.         if($nUserID != '')
  3287.             $data['reading_plan_completed_info'] = $this->getUserStepInfo($readingPlanUrl$nUserID);
  3288.         
  3289.         $nCompletedStepOrder null;
  3290.         if(isset($data['reading_plan_completed_info']['completed_step_order']))
  3291.             $nCompletedStepOrder $data['reading_plan_completed_info']['completed_step_order'];
  3292.         
  3293.         $data['completed_percentage'] = $this->getStepCompletedPercentage($readingPlanUrl$request);
  3294.                 
  3295.         $data['reading_plan_order_info'] = $this->getReadingPlanOrderInfo($readingPlanUrl);
  3296.         $data['reading_plan_url'] = $readingPlanUrl;
  3297.         $data['step_order'] = $stepOrder;
  3298.         $data['current_step_id'] = $planstep['id'];
  3299.         $bPlanStarted = ($request->getSession()->get("reading_plan_started") == || $this->hasReadingPlanStarted($readingPlanUrl,$nUserID));
  3300.         $data['plan_started'] = $bPlanStarted;
  3301.         
  3302.     /*    $bCompleted = false;
  3303.         if($stepOrder <= $nCompletedStepOrder)
  3304.             $bCompleted = true; */
  3305.         
  3306.         $nStepID $planstep['id'];    
  3307.         $bCompleted $this->IsReadingPlanStepCompleted($nStepID$request);            
  3308.         $data['step_completed'] = $bCompleted;
  3309.         $bLastUncompleted false;
  3310.         if(!$bCompleted)
  3311.             $bLastUncompleted $this->IsLastReadingPlanStepUncompleted($nStepID$request);
  3312.             
  3313.         $data['last_step_uncompleted'] = $bLastUncompleted;
  3314.         
  3315.         $bLastStep $this->IsLastReadingPlanStep($nStepID$request);
  3316.         $data['is_last_step'] = $bLastStep;
  3317.         
  3318.         if($translation !== null) {
  3319.             $work $translation->getWork();
  3320.             
  3321.             $bSwedenborgWork = ($work->getSwedenborgType() !== null);
  3322.             $data['is_swedenborg'] = $bSwedenborgWork;
  3323.             
  3324.             $bConsider false;
  3325.             $bBibleStudy false;
  3326.             $bConcept false;
  3327.             $bQA false;
  3328.             if(!$bSwedenborgWork)
  3329.             {
  3330.                 foreach($work->getCategories() as $category) {
  3331.                     if($category->getId() == $this->CATEGORY_ID_SPIRITUAL_TOPIC) {
  3332.                         $bConsider true;
  3333.                     }
  3334.                     elseif($category->getId() == $this->CATEGORY_ID_BIBLE_STUDY) {
  3335.                         $bBibleStudy true;
  3336.                     }
  3337.                     elseif($category->getId() == $this->CATEGORY_ID_CONCEPT) {
  3338.                         $bConcept true;
  3339.                         $data['category_concept'] = 1;
  3340.                     }
  3341.                     elseif($category->getId() == $this->CATEGORY_ID_QA) {
  3342.                         $bQA true;
  3343.                     }
  3344.                 }
  3345.             }
  3346.             
  3347.             $nLanguageID $translation->getLanguage()->getId();                        
  3348.             if(!$bSwedenborgWork)                
  3349.                 $data['authors'] = $this->getAuthorInfo($request$translation->getId());
  3350.             else
  3351.                 $data['IsSwedenborgWork'] = 1;    
  3352.                 
  3353.             $type_id $translation->getTypeId();
  3354.         
  3355.             if($type_id == $this->TRANSLATION_TYPE_ID_FILE
  3356.             {
  3357.                 $file $translation->getFile();
  3358.                 if($file !== null) {
  3359.                     $data['file'] = $file;
  3360.                 }
  3361.             }
  3362.             if($type_id == $this->TRANSLATION_TYPE_ID_LINK
  3363.             {
  3364.                 $doc_link $translation->getDocLink();
  3365.                 if($doc_link !== null) {
  3366.                     $data['doc_link'] = $doc_link;
  3367.                 }
  3368.             }
  3369.             
  3370.             $data['type_id'] = $type_id;
  3371.             
  3372.             $data['in_frame'] = false;
  3373.             
  3374.             if($passage != null)
  3375.             {            
  3376.                 $nTranslationID $translation->getId();
  3377.                 
  3378.                 if(!$bSwedenborgWork)
  3379.                     $data['passage_ref'] = $this->getWorkPassageRefs($nPassageID,$nTranslationID$request);
  3380.                 
  3381.                 if($bSwedenborgWork)
  3382.                     $data['related_bible_ref'] = $this->getRelatedBibleRefForWork($nPassageID,$nTranslationID$request);
  3383.                 $data['passage_footnote'] = $this->getPassageFootnotes($nPassageID,$nTranslationID);
  3384.                 $data['passage_multilink'] = $this->getWorkPassageMultiLink($nPassageID,$nTranslationID$request);
  3385.                                                    
  3386.                 $request->getSession()->set('current_explanation_cchapter_id''');                
  3387.                 $nExplainChapterID $this->getExplainChapterID($nTranslationID$this->getCurrUserID($request)); 
  3388.                   if(!empty($nExplainChapterID))
  3389.                   {                  
  3390.                       $data['cchapter_id'] = $nExplainChapterID;
  3391.                     $request->getSession()->set('current_explanation_cchapter_id'$nExplainChapterID); 
  3392.                       $request->getSession()->set('current_explanation_translation_id'$nTranslationID);
  3393.                   }
  3394.                                         
  3395.                   if($bSwedenborgWork)
  3396.                   {                              
  3397.                       $data['has_slider_item_for_work'] = $this->hasSliderItemForWork($nPassageID$nTranslationID$request$nLanguageID);
  3398.         
  3399.                     $data['slider_url'] = $this->get('router')->generate('exposition_slider', array(
  3400.                             'translationId' => $nTranslationID,
  3401.                             'passageId' => $nPassageID
  3402.                         ));
  3403.                   }    
  3404.             }
  3405.             $data['text_to_speech'] = $this->getTextToSpeech($translation->getLanguage()->getId());    
  3406.             
  3407.             if($bSwedenborgWork)   
  3408.             {     
  3409.                 $data['biblio_info'] = $this->getBiblioForTranslation($translation->getId());        
  3410.             }
  3411.             else
  3412.             {
  3413.                 // check concept image
  3414.                 if($compareTo == null)
  3415.                 {
  3416.                     $conceptUrl $this->getConceptUrl($translation->getWork()->getId());                    
  3417.                     if(!empty($conceptUrl))
  3418.                     {
  3419.                         $concept $this->getRepository('Concepts\Concept')->findOneByUrl($conceptUrl);
  3420.                         $illustrations $concept->getIllustrations();
  3421.                         $data['image'] = ($illustrations->isEmpty()) ? null $illustrations[0]->getImage();
  3422.                     }
  3423.                 }
  3424.             }    
  3425.         } else {
  3426.             $work null;
  3427.         }
  3428.         return $this->createWorkPassageView($data$work$request);
  3429.     }
  3430.     
  3431.     protected function createWorkPassageView($data$work$request)
  3432.     {
  3433.         $locale $request->getLocale();
  3434.         $response null;
  3435.         if($work === null || $data['translation'] === null || $data['passage'] === null) {
  3436.             $response = new Response();
  3437.             $response->setStatusCode(404);
  3438.             return $this->renderView('no_content', array(), $response);
  3439.         }
  3440.         
  3441.         $nPassageID $data['passage']->getId();
  3442.         $nTranslationID $data['translation']->getId();
  3443.         $nLanguageID $data['translation']->getLanguage()->getId();
  3444.         $data['translation_shortname'] = $this->getWorkTranslationShortName($nTranslationID);
  3445.         
  3446.         $nBibleBookIDForSummary $this->getBibleBookIDForSummary($nTranslationID);
  3447.         $bBibleBookSummary = ($nBibleBookIDForSummary != '');
  3448.         if($bBibleBookSummary)
  3449.             $data['is_book_summary'] = '1';
  3450.         
  3451.         if($work !== null) { 
  3452.                $nLevelID '';
  3453.                $aStory $this->getStoryInfo($nTranslationID);
  3454.             if(!empty($aStory))
  3455.             {                   
  3456.                 $nStoryID $aStory['story_id'];
  3457.                 $nLevelID $aStory['level_id'];               
  3458.                 if($nLevelID == $this->STORY_LEVEL_ID_BIBLE)
  3459.                 {  
  3460.                 //    $data['all_stories'] = $this->getExplainedStoryList($locale);
  3461.                 //    $data['story_explanations'] = $this->getWorkListForStory($locale, $nStoryID);
  3462.                     $data['commentary_type'] = 'storyexplanation';                                            
  3463.                 }
  3464.                 elseif($nLevelID == $this->STORY_LEVEL_ID_CHAPTER)
  3465.                     $data['is_chapter_explanation'] = '1';
  3466.                 elseif($nLevelID == $this->STORY_LEVEL_ID_VERSE)
  3467.                     $data['is_verse_explanation'] = '1';    
  3468.                                
  3469.                 $data['story_id'] = $nStoryID;
  3470.             }  
  3471.             // We can override the 'storyexplanation' commentary type because some "story" explanations are really verse explanations.
  3472.             // There shouldn't be any similar situation with concept explanations, so if we have an associated concept, then we'll skip the category check below.
  3473.             // The reason for not using just the category check and nothing else is in case a work or translation doesn't get put in the appropriate category.
  3474.             if($this->getConceptID($data['translation']->getId()) != null) {
  3475.                 $data['commentary_type'] = 'conceptexplanation';
  3476.             } else {
  3477.                 $containingCategories $work->getCategories()->toArray();
  3478.                 if($data['translation'] !== null) {
  3479.                     $containingCategories array_merge($containingCategories$data['translation']->getCategories()->toArray());
  3480.                 }
  3481.                 $categoryUrlToCommentaryTypeMap = array(
  3482.                     'doctrinal-topic-explanations' => 'doctrinaltopic',
  3483.                     'verse-explanations' => 'verseexplanation',
  3484.                     // The story-explanation category doesn't exist at the time of writing this as far as I know, but if it gets added later then we'll want this
  3485.                     'story-explanations' => 'storyexplanation'
  3486.                 );
  3487.                 // If the content doesn't belong to the Category for any major commentary type, then $data['commentary_type'] can just remain unset.
  3488.                 foreach($containingCategories as $cat) {
  3489.                     if(array_key_exists($cat->getUrl(), $categoryUrlToCommentaryTypeMap)) {
  3490.                         $data['commentary_type'] = $categoryUrlToCommentaryTypeMap[$cat->getUrl()];
  3491.                         // At the time of coding this, there shouldn't be anything which belongs to more than one major commentary type.
  3492.                         break;
  3493.                     }
  3494.                 }
  3495.             }
  3496.         }
  3497.                 
  3498.         if($work->getSwedenborgType() !== null)
  3499.         {              
  3500.           //  $data['previous_passage'] = $this->getPreviousPassageWithContent($data['passage'], $data['translation']);
  3501.           //  $data['next_passage'] = $this->getNextPassageWithContent($data['passage'], $data['translation']); 
  3502.             
  3503.             // Get meta description
  3504.             $nTextLength 140;            
  3505.             $sPassageText $this->getWorkPassageContents($nPassageID,$nTranslationID); 
  3506.             $sMetaDesc $this->fixWorkText($sPassageText);
  3507.               $sMetaDesc $this->getTextWithinLength($sMetaDesc$nTextLength"...");          
  3508.               $data['work_meta_desc'] = $sMetaDesc;
  3509.         } 
  3510.         else
  3511.         {
  3512.             // Get meta description
  3513.             $nTextLength 140;
  3514.             $sPassageText '';
  3515.             if($nLevelID == $this->STORY_LEVEL_ID_CHAPTER)
  3516.             {            
  3517.                 $sPassageText $this->getWorkPassageContents($nPassageID,$nTranslationID);
  3518.             }
  3519.             else
  3520.             {
  3521.                 $sPassageText $this->getWorkTranslationDesc($nTranslationID); 
  3522.                 if(empty($sPassageText))
  3523.                 {
  3524.                     $sPassageText $this->getWorkPassageContents($nPassageID,$nTranslationID); 
  3525.                 }
  3526.             }
  3527.             $sMetaDesc $this->fixWorkText($sPassageText);
  3528.               $sMetaDesc $this->getTextWithinLength($sMetaDesc$nTextLength"...");          
  3529.               $data['work_meta_desc'] = $sMetaDesc;
  3530.         }
  3531.         
  3532.         $data['work'] = $work;
  3533.                      
  3534.         return $this->renderView('work_passage'$data$response);
  3535.     }
  3536.     
  3537. /*    public function fullviewVerseAction($verseId, Request $request)
  3538.     {
  3539.         // Go to the chapter view of the verse
  3540.            $sSql = "select t.url as trans_url, cb.url as book_url, c.ordering FROM canonicalbiblechapter cc, biblebook b, biblechapter c, bibleverse v, bibletranslation t, canonicalbiblebook cb where v.id = " . $verseId . " and v.chapter_id = c.id and c.book_id = b.id and b.canonicalization_id = cc.book_id and cc.book_id = cb.id and b.translation_id = t.id and cc.ordering = c.ordering limit 1";
  3541.            
  3542.  //   echo $sSql."<br>";   
  3543.        $aData = $this->getRowData($sSql);
  3544.        $sBookUrl = trim($aData['book_url']); 
  3545.        $sTransUrl = trim($aData['trans_url']); 
  3546.        $nOrder = trim($aData['ordering']);
  3547.        $sLink = $this->get('router')->generate('bible_chapter', array(
  3548.                         'translationUrl' => $sTransUrl,
  3549.                         'bookUrl' => $sBookUrl,
  3550.                         'chapterIndex' => $nOrder                      
  3551.                     ));
  3552.             
  3553.        if(!empty($sLink))
  3554.                return $this->redirect($sLink, 301);            
  3555.        else
  3556.             return $this->redirect("/", 301);
  3557.     }
  3558. */    
  3559.     public function fullviewChapterAction($chapterIdRequest $request)
  3560.     {
  3561.         // Go to the chapter view
  3562.            $sSql "select t.url as trans_url, cb.url as book_url, c.ordering FROM canonicalbiblechapter cc, biblebook b, biblechapter c, bibletranslation t, canonicalbiblebook cb where c.id = " $chapterId " and c.book_id = b.id and b.canonicalization_id = cc.book_id and cc.book_id = cb.id and b.translation_id = t.id and cc.ordering = c.ordering limit 1";
  3563.            
  3564.  //   echo $sSql."<br>";   
  3565.        $aData $this->getRowData($sSql);
  3566.        $sBookUrl trim($aData['book_url']); 
  3567.        $sTransUrl trim($aData['trans_url']); 
  3568.        $nOrder trim($aData['ordering']);
  3569.        $sLink $this->get('router')->generate('bible_chapter', array(
  3570.                         'translationUrl' => $sTransUrl,
  3571.                         'bookUrl' => $sBookUrl,
  3572.                         'chapterIndex' => $nOrder                      
  3573.                     ));
  3574.             
  3575.        if(!empty($sLink))
  3576.                return $this->redirect($sLink301);            
  3577.        else
  3578.             return $this->redirect("/"301);
  3579.     }
  3580.     
  3581.     // For reading plan - ad-hoc
  3582.     protected function readingplanStepForAdHoc($readingPlanUrl$planstep$request)
  3583.     {       
  3584.         $this->checkIfOnMobile($request);
  3585.         $locale $request->getLocale();
  3586.         
  3587.         $nStepID $planstep['id'];            
  3588.         $nLanguageID $this->getLanguageIDByShortCode($locale);      
  3589.         $data = array(            
  3590.             'nav_mode' => 'ad-hoc',
  3591.             'text_style_override' => $this->getTextStyleOverride($nLanguageID),            
  3592.             'text_to_speech1' => $this->getTextToSpeech($nLanguageID),
  3593.             'plan_step' => $planstep        
  3594.         );
  3595.         
  3596.         $stepOrder $planstep['step_order'];        
  3597.         $data['next_reading_plan_step'] = $this->getNextReadingPlanStep($readingPlanUrl$stepOrder$request);
  3598.         $data['prev_reading_plan_step'] = $this->getPreviousReadingPlanStep($readingPlanUrl$stepOrder);
  3599.         
  3600.         $nUserID $request->getSession()->get("user_id");
  3601.         if($nUserID != '')
  3602.             $data['reading_plan_completed_info'] = $this->getUserStepInfo($readingPlanUrl$nUserID);
  3603.         
  3604.         $nCompletedStepOrder null;
  3605.         if(isset($data['reading_plan_completed_info']['completed_step_order']))
  3606.             $nCompletedStepOrder $data['reading_plan_completed_info']['completed_step_order'];
  3607.         
  3608.         $data['completed_percentage'] = $this->getStepCompletedPercentage($readingPlanUrl$request);
  3609.                 
  3610.         $data['reading_plan_order_info'] = $this->getReadingPlanOrderInfo($readingPlanUrl);
  3611.         $data['reading_plan_url'] = $readingPlanUrl;
  3612.         $data['step_order'] = $stepOrder;
  3613.         $data['current_step_id'] = $nStepID;
  3614.         $bPlanStarted = ($request->getSession()->get("reading_plan_started") == || $this->hasReadingPlanStarted($readingPlanUrl,$nUserID));
  3615.         $data['plan_started'] = $bPlanStarted;
  3616.         
  3617.     /*    $bCompleted = false;
  3618.         if($stepOrder <= $nCompletedStepOrder)
  3619.             $bCompleted = true; */
  3620.             
  3621.         $bCompleted $this->IsReadingPlanStepCompleted($nStepID$request);            
  3622.         $data['step_completed'] = $bCompleted;
  3623.         $bLastUncompleted false;
  3624.         if(!$bCompleted)
  3625.             $bLastUncompleted $this->IsLastReadingPlanStepUncompleted($nStepID$request);
  3626.             
  3627.         $data['last_step_uncompleted'] = $bLastUncompleted;
  3628.         
  3629.         $bLastStep $this->IsLastReadingPlanStep($nStepID$request);
  3630.         $data['is_last_step'] = $bLastStep;
  3631.         
  3632.         return $this->createAdHocReadingPlanStepView($data$request);
  3633.     }
  3634.     
  3635.     protected function createAdHocReadingPlanStepView($data$request)
  3636.     {
  3637.         $locale $request->getLocale();
  3638.         $response null;                
  3639.         $nLanguageID $this->getLanguageIDByShortCode($locale);
  3640.         return $this->renderView('readingplan_adhoc'$data$response);
  3641.     }
  3642.     
  3643.     public function readingPlanOutlineAction($readingPlanUrlRequest $request)
  3644.     {
  3645.         $this->onloadPage($request);    
  3646.         $locale $request->getLocale();
  3647.         $info $this->getReadingPlanInfo($readingPlanUrl,$locale);   
  3648.         $nUserID $request->getSession()->get("user_id");
  3649.         $user_plan null;
  3650.         
  3651.         $nTextLength 150;
  3652.         $sMetaDesc $this->getTextWithinLength($info['description'], $nTextLength"...");
  3653.         
  3654.         $data = array(
  3655.             'reading_plan' => $info,
  3656.             'meta_desc' => $sMetaDesc      
  3657.         );
  3658.                 
  3659.     //    $data['user_plan'] = $this->getUserReadingPlanInfo($readingPlanUrl,$nUserID, $request);
  3660.     
  3661.         $data['plan_step_list'] = $this->getReadingPlanStepsForOutline($readingPlanUrl,$nUserID$request);    
  3662.                 
  3663.         $bPlanStarted $this->hasReadingPlanStarted($readingPlanUrl,$nUserID);
  3664.         $data['plan_started'] = $bPlanStarted;
  3665.         return $this->renderView('reading_plan_outline'$data);
  3666.     }
  3667. // End of class