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

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