src/NCBS/WebsiteBundle/Controller/GeneralController.php line 255

Open in your IDE?
  1. <?php
  2. namespace NCBS\WebsiteBundle\Controller;
  3. use NCBS\WebsiteBundle\Tools\DataAssembly;
  4. use Symfony\Component\HttpFoundation\Response;
  5. use Symfony\Component\HttpFoundation\Request;
  6. class GeneralController extends NCBSWController
  7. {
  8.     protected $prefix 'General';
  9.     // Simplify the code for determining whether Bible content is using canonical numbering or not
  10.     protected $bibleCategoryIsCanonical = array('c' => false'v' => false'cc' => true'cv' => true'st' => true);
  11.     
  12.     protected $language1 null;
  13.     protected $work1 null;
  14.     public function spotlightFragmentAction($spot)
  15.     {
  16.         $method $spot.'SpotlightAction';
  17.         if(method_exists($this$method)) {
  18.             return $this->$method();
  19.         }
  20.     }
  21.     public function multicolumnAction($column1Details$column2DetailsRequest $request$column3Details null$renderingData = array())
  22.     {            
  23.         $this->onloadPage($request);
  24.         $bStory = (isset($renderingData['content_class']) && $renderingData['content_class'] == 'story');                
  25.         $this->language1 null;
  26.         $this->work1 null;
  27.         $request->getSession()->set('has_explanation_cchapter_id_temp_bible''');
  28.         $request->getSession()->set('has_explanation_cchapter_id_temp_trans''');
  29.         $request->getSession()->set('current_explanation_cchapter_id_temp_bible''');
  30.         $request->getSession()->set('current_explanation_cchapter_id_temp_trans''');
  31.         $request->getSession()->set('current_explanation_cchapter_id''');
  32.         $renderingData['columns'] = array(
  33.                 => $this->convertColumnData($column1Details1$request),
  34.                 => $this->convertColumnData($column2Details2$request)
  35.             );
  36.             
  37.         $nLastColNum 2;
  38.         $sLastColNewUrl "";   
  39.         $renderingData['multicolumn_route_params'] = array(
  40.                 'column1Details' => $column1Details,
  41.                 'column2Details' => $column2Details
  42.             );
  43.         if(empty($column3Details)) {
  44.             $renderingData['multicolumn_path'] = 'arbitrary_two_column';
  45.         } else {
  46.             $nLastColNum 3;
  47.             $renderingData['multicolumn_path'] = 'arbitrary_three_column';
  48.             $renderingData['columns'][3] = $this->convertColumnData($column3Details3$request);
  49.             $renderingData['multicolumn_route_params']['column3Details'] = $column3Details;
  50.         }
  51.         $curr_book null;
  52.         $story_translation_url null;
  53.         $explained_verse null;
  54.         $first_col_chapter_id null;
  55.         $bExplainedChapter false;
  56.         $first_col_verse_id null;
  57.         $bExplainedVerse false;
  58.         $bExplainedVersePage false// The explanation is for the verse on column 1
  59.         foreach($renderingData['columns'] as $columnNum => $columnDetails) {
  60.             if(empty($columnDetails)|| $columnDetails['column_type'] === 'unrecognized')
  61.             {
  62.                 $response = new Response();
  63.                 $response->setStatusCode(404);
  64.                 return $this->renderView('no_content_back', array(), $response);
  65.             }         
  66.         
  67.             $columnDetails['column_number'] = $columnNum;
  68.             if($columnDetails['column_type'] === 'dependent') {
  69.                 return $this->assembleMulticolumnWithDependencies($renderingData$column1Details$column2Details$request$column3Details);
  70.             }
  71.             if($columnDetails['column_type'] === 'bible') {
  72.                 //$chapterExplanation = $columnDetails['chapter_explanations_for_commentary'];  
  73.                 $curr_book null;
  74.                 if(isset($columnDetails['curr_book']))
  75.                     $curr_book $columnDetails['curr_book']; 
  76.                     
  77.                 $story_translation_url $columnDetails['story_translation_url'];   
  78.                 if($columnNum == 1)
  79.                 {
  80.                     $explained_verse $columnDetails['explained_verse']; 
  81.                     
  82.                     if($columnDetails['content_category'] == 'c')
  83.                         $first_col_chapter_id $columnDetails['chapter_id'];
  84.                         
  85.                     if($columnDetails['content_category'] == 'v')
  86.                         $first_col_verse_id $columnDetails['verse_id'];    
  87.                 }    
  88.            
  89.                 if(empty($column3Details) && $columnNum == && isset($columnDetails['verse_meta_desc']))
  90.                     $renderingData['verse_meta_desc'] = $columnDetails['verse_meta_desc'];         
  91.             }
  92.             elseif($columnDetails['column_type'] === 'exposition') {
  93.                 //$renderingData['chapter_explanations'] = $chapterExplanation;
  94.                 if(isset($columnDetails['translation']) && $columnDetails['translation'] != null) {                   
  95.                    $translation_id $columnDetails['translation']->getId();
  96.                    if($columnNum == $nLastColNum && @$_GET["fs"] == 1)
  97.                    {
  98.                            $passage_id $columnDetails['passage']->getId();
  99.                         $sLastColNewUrl $this->getNewWorkTranslationUrl($translation_id$passage_id);            
  100.                         if(!empty($sLastColNewUrl))
  101.                         {
  102.                             break;
  103.                         }            
  104.                    }
  105.                    $nBibleBookIDForSummary $this->getBibleBookIDForSummary($translation_id);
  106.                    $bBibleBookSummary = ($nBibleBookIDForSummary != '');
  107.                    $aBibleBookSummaryList null;
  108.                    if($bBibleBookSummary)
  109.                    {
  110.                            $aBibleBookSummaryList $this->getBibleBookSummaryList($nBibleBookIDForSummary);
  111.                            
  112.                            if(!empty($aBibleBookSummaryList))
  113.                                $renderingData['book_id_for_summaries'] = $nBibleBookIDForSummary;
  114.                    }
  115.                    
  116.                    $renderingData['book_summaries'] = $aBibleBookSummaryList;
  117.                    
  118.                    $tempchapterExplanation null;
  119.                    $tempchapterExplanationForCombo null;
  120.                    if(!$bBibleBookSummary)
  121.                    {
  122.                        if($curr_book != null)
  123.                        {
  124.                                $tempchapterExplanation $this->getChapterExplanations($curr_book$columnDetails['translation'], $request);
  125.                                $tempchapterExplanationForCombo $this->getChapterExplanationsForCombo($curr_book$columnDetails['translation']);
  126.                                
  127.                                $renderingData['explained_book'] = $curr_book;
  128.                            }    
  129.                            else
  130.                            {
  131.                                $tempchapterExplanation $this->getChapterExplanationsForText($columnDetails['translation']);    
  132.                                $tempchapterExplanationForCombo $tempchapterExplanation;
  133.                            }    
  134.                         if($tempchapterExplanation != null)
  135.                         {                    
  136.                             $renderingData['chapter_explanations'] = $tempchapterExplanation;
  137.                             $columnDetails['chapter_explanations'] = $tempchapterExplanation;
  138.                             
  139.                             $renderingData['chapter_explanations_for_combo'] = $tempchapterExplanationForCombo;
  140.                             
  141.                             if($columnNum == && $first_col_chapter_id != null && $curr_book != null)
  142.                             {
  143.                                 foreach($tempchapterExplanation as $explanation)
  144.                                 {                  
  145.                                     if($explanation['chapter_id'] == $first_col_chapter_id)
  146.                                     { 
  147.                                         $bExplainedChapter true;
  148.                                         break;
  149.                                     }    
  150.                                 }
  151.                             }
  152.                         }    
  153.                         
  154.                         if($columnNum && $explained_verse != null)
  155.                         {       
  156.                             if($columnNum == && !empty($first_col_verse_id))  
  157.                                 $bExplainedVersePage $this->isExplainedVerse($translation_id$first_col_verse_id); 
  158.                             
  159.                             $tempVerse_explanations $this->getVerseExplanations($explained_verse['chapter_id'], $explained_verse['language_id'], $request);                   
  160.                             $renderingData['verse_explanations'] = $tempVerse_explanations;
  161.                             $renderingData['chapter_id_for_verse_explanation'] = $explained_verse['chapter_id'];
  162.                             $renderingData['language_id_for_verse_explanation'] = $explained_verse['language_id'];
  163.                             
  164.                             foreach($tempVerse_explanations as $explanation)
  165.                             {                  
  166.                                 if($explanation['verse_id'] == $first_col_verse_id)
  167.                                 { 
  168.                                     $bExplainedVerse true;
  169.                                     break;
  170.                                 }    
  171.                             }                            
  172.                         }    
  173.                     } 
  174.                 }              
  175.                 if($story_translation_url != null)
  176.                 {
  177.                     $renderingData['story_translation_url'] = $story_translation_url
  178.                 } 
  179.              
  180.                  if($bStory)
  181.                  {
  182.                      $nTextLength 140;
  183.                      $sTransText $this->getWorkTranslationDesc($translation_id);
  184.                      if(empty($sTransText))
  185.                      {
  186.                          $sTransText $this->getExplanationContents($translation_id);
  187.                      }
  188.                      
  189.                      $sMetaDesc $this->fixWorkText($sTransText);
  190.                       $sMetaDesc $this->getTextWithinLength($sMetaDesc$nTextLength"...");
  191.                       $renderingData['story_meta_desc'] = $sMetaDesc;
  192.                  }
  193.                  else if(empty($column3Details) && $columnNum == && isset($renderingData['verse_meta_desc']))
  194.                  {
  195.                      if($bExplainedVersePage)
  196.                      {
  197.                          $sTransTitle $columnDetails['translation']->getTranslatedTitle();
  198.                         $renderingData['verse_explanation_meta_desc'] = $sTransTitle " - "$renderingData['verse_meta_desc'];
  199.                     }                    
  200.                 }          
  201.             }
  202.         }
  203.         
  204.         if(!empty($sLastColNewUrl))
  205.         {
  206.             // redirect
  207.             $renderingData['multicolumn_route_params']['column'.$nLastColNum.'Details'] = $sLastColNewUrl;
  208.             return $this->redirect($this->get('router')->generate($renderingData['multicolumn_path'], $renderingData['multicolumn_route_params']), 301);
  209.         }
  210.         if($bExplainedChapter)
  211.         {   
  212.             foreach($renderingData['columns'] as $columnNum => $columnDetails) { 
  213.                 if($columnDetails['column_type'] === 'bible' && $columnNum == 1) {               
  214.                     $renderingData['chapter_explanation_page'] = true;  
  215.                     break;       
  216.                 }
  217.             }
  218.         }
  219.         else if($bExplainedVerse)
  220.         {   
  221.             foreach($renderingData['columns'] as $columnNum => $columnDetails) {            
  222.                 if($columnDetails['column_type'] === 'bible' && $columnNum == 1) {               
  223.                     $renderingData['verse_explanation_page'] = true;
  224.                     break;         
  225.                 }
  226.             }
  227.         }
  228.         
  229.         $this->setCurrentUrl($request); 
  230.                 
  231.         $nTempChapterID_Bible $request->getSession()->get('current_explanation_cchapter_id_temp_bible');
  232.         $nTempChapterID_Trans $request->getSession()->get('current_explanation_cchapter_id_temp_trans');   
  233.         if($nTempChapterID_Trans != '')
  234.         {
  235.             $nTempTransID_Trans $request->getSession()->get('current_explanation_translation_id_temp_trans'); 
  236.             $request->getSession()->set('current_explanation_cchapter_id'$nTempChapterID_Trans);
  237.             $request->getSession()->set('current_explanation_translation_id'$nTempTransID_Trans);
  238.         }    
  239.         else if($nTempChapterID_Bible != '')
  240.         {
  241.             $nTempTransID_Bible $request->getSession()->get('current_explanation_translation_id_temp_bible');
  242.             $request->getSession()->set('current_explanation_cchapter_id'$nTempChapterID_Bible);
  243.             $request->getSession()->set('current_explanation_translation_id'$nTempTransID_Bible);
  244.         }    
  245.                 
  246.         // If no dependencies, can proceed with normal page generation
  247.         return $this->createMulticolumnView($renderingData$request);
  248.     }
  249.     protected function assembleMulticolumnWithDependencies($renderingData$column1Details$column2DetailsRequest $request$column3Details null)
  250.     {
  251.         $numColumns count($renderingData['columns']);
  252.         // We want an array of column dependencies for each column; a non-dependent column doesn't have its own, so we'll patch in this array:
  253.         $noDependencies = array(=> 'none'=> 'none'=> 'none');
  254.         // This array says which columns have any dependencies at all (used to determine if we need to process dependencies in the first place)
  255.         $isDependent = array();
  256.         // And this array says exactly which columns depend on which other ones, and how
  257.         $columnDependencies = array();
  258.         // While we set up those arrays, we'll try to resolve optional self-dependencies that don't have other dependencies attached
  259.         foreach($renderingData['columns'] as $columnNum => $columnData) {
  260.             if($columnData['column_type'] === 'dependent') {
  261.                 $columnDependencies[$columnNum] = $columnData['depends_on'];
  262.                 $onlyOptionalSelfDependency true;
  263.                 foreach($columnDependencies[$columnNum] as $dependencyColumnNum => $dependencyType) {
  264.                     // Need == here instead of === because we might be comparing strings to integers
  265.                     if( ($dependencyColumnNum == $columnNum && $dependencyType !== 'optional')
  266.                         || ($dependencyColumnNum != $columnNum && $dependencyType !== 'none')
  267.                     ) {
  268.                         $onlyOptionalSelfDependency false;
  269.                     }
  270.                 }
  271.                 if($onlyOptionalSelfDependency) {
  272.                     $columnDetailVar 'column'.$columnNum.'Details';
  273.                     $columnData $this->convertColumnData($columnDetailVar$columnNum$request$columnNum$renderingData);
  274.                     $renderingData['columns'][$columnNum] = $columnData;
  275.                     if($columnData['column_type'] === 'dependent') {
  276.                         $columnDependencies[$columnNum] = $columnData['depends_on'];
  277.                     } else {
  278.                         $columnDependencies[$columnNum] = $noDependencies;
  279.                     }
  280.                 }
  281.             } else {
  282.                 $columnDependencies[$columnNum] = $noDependencies;
  283.             }
  284.             $isDependent[$columnNum] = $columnData['column_type'] === 'dependent';
  285.         }
  286.         // Double-check that we actually need to resolve dependencies (i.e. at least one column is dependent)
  287.         if(!in_array(true$isDependent)) {
  288.             return $this->createMulticolumnView($renderingData$request);
  289.         }
  290.         // Check for cycles: make sure no column that has a required dependency on itself ...
  291.         if( ($columnDependencies[1][1] === 'required')
  292.             || ($columnDependencies[2][2] === 'required')
  293.             || ($numColumns === && $columnDependencies[3][3] === 'required')
  294.         ) {
  295.             throw new \Exception('Invalid column specification: Required self-dependency');
  296.         }
  297.         // ... at least one column can, if necessary, be built without using dependencies ...
  298.         $numRequiredDependencies 0;
  299.         if($columnDependencies[1][2] === 'required' || $columnDependencies[1][3] === 'required') {
  300.             $numRequiredDependencies++;
  301.         }
  302.         if($columnDependencies[2][1] === 'required' || $columnDependencies[2][3] === 'required') {
  303.             $numRequiredDependencies++;
  304.         }
  305.         if($numColumns === && ($columnDependencies[3][1] === 'required' || $columnDependencies[3][1] === 'required')) {
  306.             $numRequiredDependencies++;
  307.         }
  308.         if($numRequiredDependencies === $numColumns) {
  309.             throw new \Exception('Invalid column specification: All columns have required dependencies');
  310.         }
  311.         // ... and no mutual required dependencies
  312.         // (Note: if there are 2 columns, we will have already caught this case because all columns are dependent)
  313.         if($numColumns === && (
  314.                 ($columnDependencies[1][2] === 'required' && $columnDependencies[2][1] === 'required')
  315.                 || ($columnDependencies[1][3] === 'required' && $columnDependencies[3][1] === 'required')
  316.                 || ($columnDependencies[2][3] === 'required' && $columnDependencies[3][2] === 'required')
  317.         )) {
  318.             throw new \Exception('Invalid column specification: Two columns depend on each other');
  319.         }
  320.         // Also, let's make sure there are no required dependencies on the third column if it doesn't exist
  321.         if($numColumns === && ($columnDependencies[1][3] === 'required' || $columnDependencies[2][3] === 'required')) {
  322.             throw new \Exception('Invalid column specification: Required dependency on a nonexistent column');
  323.         }
  324.         // At this point, we have made sure that:
  325.         // (a) at least one dependency needs to be resolved
  326.         // (b) there is a way to acceptably resolve all dependencies
  327.         // Now we need to actually do the dependency resolution
  328.         // (keeping in mind that we should have already resolved optional self-dependencies).
  329.         if($numColumns === 2) {
  330.             // If only two total columns, then there can only be one required dependency (or we would have thrown an exception earlier)
  331.             // ... but there still might be mutual dependencies if at least one is optional, in which case we must process the optional dependency first.
  332.             // So we'll process optional dependencies first, then required dependencies.
  333.             // In case of mutual optional dependencies, this code should work OK, simply by arbitrarily processing column 1 first.
  334.             // In other cases, it will work because there will only be one dependency at most.
  335.             if($columnDependencies[1][2] === 'optional') {
  336.                 $renderingData['columns'][1] = $this->convertColumnData($column1Details1$request1$renderingData);
  337.             }
  338.             if($columnDependencies[2][1] === 'optional') {
  339.                 $renderingData['columns'][2] = $this->convertColumnData($column2Details2$request2$renderingData);
  340.             }
  341.             if($columnDependencies[1][2] === 'required') {
  342.                 $renderingData['columns'][1] = $this->convertColumnData($column1Details1$request1$renderingData);
  343.             }
  344.             if($columnDependencies[2][1] === 'required') {
  345.                 $renderingData['columns'][2] = $this->convertColumnData($column2Details2$request2$renderingData);
  346.             }
  347.             return $this->createMulticolumnView($renderingData$request);
  348.         }
  349.         /*
  350.          * If we get to this point, then we should have three columns.
  351.          * We'll use the following priority list to process one column at a time until there are no more to process:
  352.          * 1. If possible, process a column which doesn't depend on other columns that also have dependencies.
  353.          *    (In other words, it depends only on non-dependent columns and/or itself.)
  354.          * 2. If no such column exists, process a column that meets similar criteria, except that it:
  355.          *    (a) can also have optional dependencies on columns that have required dependencies
  356.          *    (b) MUST have another column that depends on it
  357.          * 3. If no column fits either of the first two cases, process any column that doesn't have a required dependency on a dependent column.
  358.          *
  359.          * These criteria will always match at least one column, as long as there isn't a required dependency loop,
  360.          * and are intended to maximize the likelihood that required dependencies will have appropriate content in the column they depend on.
  361.          * (They probably aren't the best possible rules, but they should at least work well for all common cases and not completely break even in corner cases.)
  362.          *
  363.          * The numbers 1, 2, 3 are used in some places in the code below to indicate the priority tiers given above.
  364.          */
  365.         $strongestDependencies = array(=> 'none'=> 'none'=> 'none');
  366.         foreach($columnDependencies as $columnNum => $columnDependsOn) {
  367.             if(in_array('required'$columnDependsOn)) {
  368.                 $strongestDependencies[$columnNum] = 'required';
  369.             } elseif(in_array('optional'$columnDependsOn)) {
  370.                 $strongestDependencies[$columnNum] = 'optional';
  371.             }
  372.         }
  373.         for($numProcessed 0; ; $numProcessed++) {
  374.             // When no columns have dependencies left, we can stop with dependency resolution and return to normal view generation
  375.             if($strongestDependencies[1] === 'none' && $strongestDependencies[2] === 'none' && $strongestDependencies[3] === 'none') {
  376.                 return $this->createMulticolumnView($renderingData$request);
  377.             }
  378.             if($numProcessed >= 6) {
  379.                 // If we reach this, then on average, we've run convertColumnData TWICE PER COLUMN and still haven't resolved everything!
  380.                 // So we'll throw in a failsafe in case we somehow get into an infinite loop
  381.                 throw new \Exception('Unexpected error: Excessive repeated processing of dependencies');
  382.             }
  383.             $topPriorityRank 99// where 99 is just an arbitrary number later than any priority we actually use
  384.             $topPriorityColumnNum null;
  385.             foreach($renderingData['columns'] as $columnNum => $columnData) {
  386.                 // Non-dependent columns can't be candidates for processing
  387.                 if($columnData['column_type'] !== 'dependent') {
  388.                     continue;
  389.                 }
  390.                 $runningPriorityMeasure 1;
  391.                 foreach($columnData['depends_on'] as $otherColumnNum => $dependencyLevel) {
  392.                     /*
  393.                      * The following don't affect priority:
  394.                      * (optional) self-dependencies
  395.                      * columns that this column doesn't depend on
  396.                      * dependencies on non-dependent columns
  397.                      */
  398.                     if($otherColumnNum == $columnNum || $dependencyLevel === 'none' || $strongestDependencies[$otherColumnNum] === 'none') {
  399.                         continue;
  400.                     } elseif($dependencyLevel === 'required') {
  401.                         // We know the other column is dependent (or else we would have fallen into the previous if case).
  402.                         // A column with a required dependency on a dependent column is never a candidate for dependency resolution.
  403.                         continue 2;
  404.                     } elseif($strongestDependencies[$otherColumnNum] === 'optional') {
  405.                         // A dependency on a column with optional dependencies knocks this column to priority 3
  406.                         $runningPriorityMeasure 3;
  407.                     } elseif($runningPriorityMeasure === 1) {
  408.                         // Here, we know this is an optional dependency (or else we would have hit the first or second case)
  409.                         // on a column that has a required dependency (or else we would have hit the first or third case).
  410.                         // Such a thing can't exist in priority case 1, but can exist in priority case 2.
  411.                         $runningPriorityMeasure 2;
  412.                     }
  413.                 }
  414.                 // The above loop figures out where this column's outgoing dependencies fit into the priority scheme.
  415.                 // For priority 2, we also need to check whether the column has an incoming dependency.
  416.                 if($runningPriorityMeasure === 2) {
  417.                     // We'll temporarily set priority to 3, then revert to 2 if we find an incoming dependency
  418.                     $runningPriorityMeasure 3;
  419.                     foreach($columnDependencies as $sourceColumnNum => $dependencyData) {
  420.                         if($sourceColumnNum == $columnNum) {
  421.                             // Self-dependencies don't count here
  422.                             continue;
  423.                         } elseif($dependencyData[$columnNum] !== 'none') {
  424.                             // Incoming dependency! No need to continue the loop now that we know such a dependency exists.
  425.                             $runningPriorityMeasure 2;
  426.                             break;
  427.                         }
  428.                     }
  429.                 }
  430.                 // The value of $runningPriorityMeasure should now indicate the final priority for this column.
  431.                 // If it's an earlier priority than our previous best, then set this column as the new first priority.
  432.                 if($runningPriorityMeasure $topPriorityRank) {
  433.                     $topPriorityRank $runningPriorityMeasure;
  434.                     $topPriorityColumnNum $columnNum;
  435.                 }
  436.             } // end "find column with top priority" loop foreach($renderingData['columns'] as $columnNum => $columnData)
  437.             if($topPriorityColumnNum !== null) {
  438.                 $columnDetailVar 'column'.$topPriorityColumnNum.'Details';
  439.                 $newColumnData $this->convertColumnData($columnDetailVar$topPriorityColumnNum$request$topPriorityColumnNum$renderingData);
  440.                 $renderingData['columns'][$topPriorityColumnNum] = $newColumnData;
  441.                 if($newColumnData['column_type'] === 'dependent') {
  442.                     $columnDependencies[$topPriorityColumnNum] = $newColumnData['depends_on'];
  443.                     if(in_array('required'$newColumnData['depends_on'])) {
  444.                         $strongestDependencies[$topPriorityColumnNum] = 'required';
  445.                     } else {
  446.                         $strongestDependencies[$topPriorityColumnNum] = 'optional';
  447.                     }
  448.                 } else {
  449.                     $columnDependencies[$topPriorityColumnNum] = $noDependencies;
  450.                     $strongestDependencies[$topPriorityColumnNum] = 'none';
  451.                 }
  452.             } else {
  453.                 // There must be SOME dependency, or else we would have broken the loop near the beginning of the iteration.
  454.                 // But we haven't found any column that matches any of our criteria for choosing which column to process ...
  455.                 throw new \Exception('Unexpected error: Expected a resolvable column dependency but could not find one');
  456.             }
  457.         } // end dependency processing loop for($numProcessed = 0; ...)
  458.     }
  459.     protected function createMulticolumnView($renderingData$request)
  460.     {
  461.         // Certain types of content require additional data for certain purposes -- e.g. Bible content needs a list of all Bible translations
  462.         $this->checkIfOnMobile($request); 
  463.         $locale $request->getLocale();
  464.         $hasBible false;
  465.         $hasSwedenborg false;
  466.         $hasOther false;
  467.         $hasStory false;
  468.         $nStoryID null;
  469.         $book_translation null;
  470.         $book null;
  471.         $sCommentaryUrl null;
  472.         foreach($renderingData['columns'] as $columnNum => $singleColumnData) {
  473.             if($singleColumnData['column_type'] === 'bible') {
  474.                 $hasBible true;
  475.                 $book_translation $singleColumnData['translation'];
  476.                 $book $singleColumnData['book'];
  477.                 
  478.                 if(isset($singleColumnData['content_category']) && $singleColumnData['content_category'] === 'st')
  479.                     $hasStory true;    
  480.             } elseif($singleColumnData['column_type'] === 'exposition' && !isset($singleColumnData['translation'])) {
  481.                 // Do nothing (specifically, don't try to use $singleColumnData['translation'] in the next two clauses)                
  482.             } elseif($singleColumnData['column_type'] === 'exposition') {
  483.                 if($this->isSwedenborg($singleColumnData['translation']->getId()))
  484.                     $hasSwedenborg true;
  485.                 else
  486.                     $hasOther true;    
  487.             } 
  488.             elseif($singleColumnData['column_type'] === 'exposition'
  489.             {     
  490.                 //$aStory = $singleColumnData['translation']->getWork()->getStories();
  491.                 $aStory $this->getStoryInfo($singleColumnData['translation']->getId());
  492.                 if(!empty($aStory))
  493.                 {                   
  494.                     $nLevelID $aStory['level_id'];               
  495.                     if($nLevelID == $this->STORY_LEVEL_ID_BIBLE)
  496.                     {  
  497.                         $hasStory true;                                             
  498.                     }
  499.                     elseif($nLevelID == $this->STORY_LEVEL_ID_CHAPTER)
  500.                         $renderingData['is_chapter_explanation'] = '1';
  501.                     elseif($nLevelID == $this->STORY_LEVEL_ID_VERSE)
  502.                         $renderingData['is_verse_explanation'] = '1';    
  503.                     
  504.                     $nStoryID $aStory['story_id'];
  505.                     $renderingData['story_id'] = $nStoryID;
  506.                     
  507.                     $sCommentaryUrl "";                    
  508.                     if(isset($singleColumnData['translation_url']))                        
  509.                         $sCommentaryUrl $singleColumnData['translation_url']; 
  510.                 }    
  511.             }
  512.             // While we're looping through the columns, we'll also find and apply any uri overrides (used e.g. with story explanations)
  513.             if(array_key_exists('column_uri_override'$singleColumnData)) {
  514.                 $renderingData['multicolumn_route_params']['column'.$columnNum.'Details'] = $singleColumnData['column_uri_override'];
  515.             }
  516.             // Also, check for unresolved dependencies
  517.             if($singleColumnData['column_type'] === 'dependent') {
  518.                 $singleColumnData['errors'][] = array('code' => '500''message' => 'unresolveddependency');
  519.             }
  520.         }
  521.   
  522.  /*       if($hasSwedenborg) {
  523.            // $renderingData['swedenborg_works'] = $this->getCategorizedSwedenborgWorks($request);
  524.         } */
  525.         if($hasStory && $nStoryID != null) {
  526.             $aAllStory = array();
  527.             $aSearchedStory $request->getSession()->get('searched_bible_story_list');
  528.             if(!empty($aSearchedStory))
  529.             {
  530.                 foreach($aSearchedStory as $s)
  531.                 {                
  532.                     if($s['commentary_url'] == $sCommentaryUrl)
  533.                     {
  534.                         $aAllStory $aSearchedStory;
  535.                         break;
  536.                     }
  537.                 }
  538.             }
  539.             
  540.             if(empty($aAllStory))
  541.             {
  542.                 $aAllStory $this->getExplainedStoryList($locale);
  543.             }
  544.         //    print_r($aAllStory);
  545.             $renderingData['all_stories'] = $aAllStory;
  546.             $renderingData['story_explanations'] = $this->getWorkListForStory($locale$nStoryID);
  547.             $renderingData['story_id'] = $nStoryID;
  548.                         
  549.             if(!empty($book_translation))
  550.                 $renderingData['book_translation_url'] = $book_translation['url'];
  551.                 
  552.            // if(!empty($sCommentaryUrl))
  553.                 $renderingData['commentary_url'] = $sCommentaryUrl;    
  554.         }
  555.         $response null;
  556.         $returnErrorStatusCode null;
  557.         foreach($renderingData['columns'] as $columnNum => $singleColumnData) {
  558.             if(array_key_exists('errors'$singleColumnData)) {
  559.                 foreach($singleColumnData['errors'] as $error) {
  560.                     // If different columns have different problems, we can still only send one HTTP status code.
  561.                     // Coincidentally, among the four most likely error codes, it's better to send the lower-numbered ones:
  562.                     // 301 (permanent redirect) over 302 (temporary redirect) over 404 (not found) over 500 (server error)
  563.                     // (note that this does NOT work with code 200 (OK), which we don't want to use if there's anything remotely like an error)
  564.                     if($returnErrorStatusCode === null || $error['code'] < $returnErrorStatusCode) {
  565.                         $returnErrorStatusCode $error['code'];
  566.                     }
  567.                 }
  568.             }
  569.         }
  570.         if($returnErrorStatusCode !== null) {
  571.             $response = new Response();
  572.             $response->setStatusCode($returnErrorStatusCode);
  573.         }
  574.         $nLinkTypeID $this->LINK_TYPE_ID_OTHER;
  575.         if(!$hasOther)
  576.         {
  577.             if($hasBible && !$hasSwedenborg)
  578.             {
  579.                 $nLinkTypeID $this->LINK_TYPE_ID_BIBLE;
  580.             }
  581.             else if(!$hasBible && $hasSwedenborg)
  582.             {
  583.                 $nLinkTypeID $this->LINK_TYPE_ID_SWEDENBORG;
  584.             }
  585.         }
  586.         $renderingData['linktype_id'] = $nLinkTypeID;
  587.         
  588.         return $this->renderView('multicolumn/generic_multicolumn'$renderingData$response);
  589.     }
  590.     protected function convertColumnData($columnDetails$column_number$request$targetColumnNum null$renderingData null)
  591.     {
  592.         $dataElementDetails explode('_'strtolower($columnDetails));
  593.         $domainIndicator array_shift($dataElementDetails);
  594.         if($domainIndicator === $this->MULTI_URL_INDICATOR_BIBLE || $domainIndicator === $this->MULTI_URL_INDICATOR_BIBLE_STORYTEXT) {
  595.             return $this->bibleColumnDataNew($columnDetails$column_number$request$targetColumnNum$renderingData);
  596.         }
  597.         else if($domainIndicator === $this->MULTI_URL_INDICATOR_SWEDENBORG_WORK || $domainIndicator === $this->MULTI_URL_INDICATOR_EXPLANATION) {
  598.             return $this->expositionColumnDataNew($columnDetails$column_number$request$targetColumnNum$renderingData);
  599.         }
  600.         else
  601.         {        
  602.             // old functions, keep them for bible stories
  603.     /*        if($domainIndicator === 'b') {
  604.                 return $this->bibleColumnData($dataElementDetails, $column_number, $request, $targetColumnNum, $renderingData);
  605.             }
  606.             else if($domainIndicator === 'e') {
  607.                 return $this->expositionColumnData($dataElementDetails, $column_number, $request, $targetColumnNum, $renderingData);
  608.             } */
  609.         }
  610.         return $this->badColumnRequestData($columnDetails$targetColumnNum$renderingData);
  611.     }
  612.     protected function badColumnRequestData($columnDetails$targetColumnNum$renderingData)
  613.     {
  614.         $rval = array('column_type' => 'unrecognized');
  615.         $rval['errors'][] = array('code' => 404'message' => 'badcolumnrequest');
  616.         return $rval;
  617.     }
  618.     protected function bibleColumnData($columnSpec$column_number$request$targetColumnNum null$renderingData null)
  619.     {
  620.         // Possible formats:
  621.         // b_c_### (chapter by id)
  622.         // b_c_###-### (chapter range by ids)
  623.         // b_v_### (verse by ids)
  624.         // b_v_###-### (verse range by ids, possibly spanning multiple chapters)
  625.         // To use canonical numbering, replace "c" with "cc" or "v" with "cv" in the above
  626.         // b_st_### (bible text for the story with the given id)
  627.         // Canonical-numbered content (including stories) will use default or arbitrary translation; adding "_###" to the end specifies the translation ID
  628.         
  629. //echo 'ttt1:'.time();
  630.         $contentCategory array_shift($columnSpec);
  631.         $isCanonical $this->bibleCategoryIsCanonical[$contentCategory];
  632.         $contentIds explode('-'array_shift($columnSpec));
  633.         $chapterExplanation null;
  634.         $qbible_link null;
  635.         $verses null;
  636.         $translation = array();
  637.         $nChapterId null;
  638.         $nVerseId null;
  639.         $nextChapter null;
  640.           $prevChapter null;
  641.           $nextVerse null;
  642.           $prevVerse null;
  643.           $chapterStartIndex null;
  644.           $bChapterLevel false;
  645.         $bVerseLevel false;
  646.         if($contentCategory === 'c' || $contentCategory === 'cc') { 
  647.             $bChapterLevel true;
  648.             $nChapterId array_shift($contentIds);       
  649.             $translation $this->getBibleTranslationByChapter($nChapterId$isCanonical);
  650.             $chapterRepos $this->bibleData($isCanonical 'Canonical\Chapter' 'Chapter');
  651.             $firstChapter $chapterRepos->findOneById($nChapterId);
  652.             if($firstChapter !== null) {
  653.                 $book $firstChapter->getBook();
  654.                 $chapterStartIndex $firstChapter->getOrdering();
  655.                 if(empty($contentIds)) {
  656.                     $lastChapter null;
  657.                     $chapterEndIndex null;
  658.                 } else {
  659.                     $lastChapter $chapterRepos->findOneById(array_shift($contentIds));
  660.                     $chapterEndIndex $lastChapter->getOrdering();
  661.                 }
  662.             } else {
  663.                 return array();
  664.          /*       $book = null;
  665.                 $lastChapter = null;
  666.                 $chapterStartIndex = null;
  667.                 $chapterEndIndex = null; */
  668.             }
  669.             $verseStartIndex null;
  670.             $verseEndIndex null;
  671.             $rangeStart $firstChapter;
  672.             $rangeEnd $lastChapter
  673.             
  674.             if($chapterExplanation == null && !empty($translation))
  675.             {            
  676.                 // get chapter explanation    
  677.                 $chapterExplanation $this->getChapterExplanation($translation['chapter_id'], $translation['url'], $request); 
  678.                 $nextChapter $this->getNextChapter($nChapterId);
  679.                   $prevChapter $this->getPreviousChapter($nChapterId);
  680.             }
  681.         } elseif($contentCategory === 'v' || $contentCategory === 'cv' || $contentCategory === 'st') {
  682.             if($contentCategory === 'st') {
  683.                 $storyId array_shift($contentIds);
  684.                 if(empty($storyId)) {
  685.                     $story null;
  686.                     $firstVerse null;
  687.                     $lastVerse null;
  688.                 } else {
  689.                     $story $this->bibleData('Stories\Story')->findOneBy(array('id' => $storyId'level_id' => $this->STORY_LEVEL_ID_BIBLE'isPublic' => true));
  690.                     if($story === null) {
  691.                         $firstVerse null;
  692.                         $lastVerse null;
  693.                     } else {
  694.                         $firstVerse $story->getStartVerse();
  695.                         $lastVerse $story->getEndVerse();
  696.                     }
  697.                 }
  698.             } else {     
  699.                 $bVerseLevel false;       
  700.                 $verseRepos $this->bibleData($isCanonical 'Canonical\Verse' 'Verse');
  701.                 $nVerseId array_shift($contentIds);
  702.                 $firstVerse $verseRepos->findOneById($nVerseId);
  703.                 $lastVerse = empty($contentIds) ? null $verseRepos->findOneById(array_shift($contentIds));
  704.                 if(!$isCanonical) {
  705.                     if($firstVerse !== null) {
  706.                         $firstVerse $firstVerse->findMainVerse();
  707.                     }
  708.                     if($lastVerse !== null) {
  709.                         $lastVerse $lastVerse->findMainVerse();
  710.                     }                                        
  711.              
  712.                     if($chapterExplanation == null)
  713.                     {                     
  714.                         $firstChapter $firstVerse->getChapter(); 
  715.                         $nChapterId $firstChapter->getCanonicalization()->getId();                    
  716.                         $nextChapter $this->getNextChapter($firstChapter->getId());
  717.                           $prevChapter $this->getPreviousChapter($firstChapter->getId());
  718.                     }                        
  719.                 }    
  720.                 
  721.                 if($nVerseId != null && $nVerseId != '')
  722.                 {
  723.                     $nextVerse $this->getNextVerse($nVerseId);
  724.                       $prevVerse $this->getPreviousVerse($nVerseId); 
  725.                   }            
  726.             }
  727.             if($firstVerse !== null) {
  728.                 $firstChapter $firstVerse->getChapter();
  729.                 $book $firstChapter->getBook();
  730.                 $chapterStartIndex $firstChapter->getOrdering();
  731.                 $verseStartIndex $contentCategory === 'v' $firstVerse->getIndexDisplay() : $firstVerse->getOrdering();
  732.                 if($lastVerse === null) {
  733.                     $chapterEndIndex null;
  734.                     $verseEndIndex null;
  735.                 } else {
  736.                     $chapterEndIndex $lastVerse->getChapter()->getOrdering();
  737.                     $verseEndIndex $contentCategory === 'v' $lastVerse->getIndexDisplay() : $lastVerse->getOrdering();
  738.                 }
  739.             } else {
  740.                 $book null;
  741.                 $chapterStartIndex null;
  742.                 $verseStartIndex null;
  743.                 $chapterEndIndex null;
  744.                 $verseEndIndex null;
  745.             }
  746.             $rangeStart $firstVerse;
  747.             $rangeEnd $lastVerse;
  748.         }
  749.         $nNewBookID null;
  750.         $nTranslationID null;
  751.         // If canonical, convert to translation
  752.         if($contentCategory === 'cc' || $contentCategory === 'cv' || $contentCategory === 'st') {
  753.             if(empty($columnSpec)) {
  754.                 // default or arbitrary translation
  755.                 // TODO: Select language-default translation for current or default language, or use last viewed translation
  756.                 $nLanguageID null;
  757.                 if($this->language1 !== null)
  758.                     $nLanguageID $this->language1->getId();
  759.                   
  760.                      
  761.                 if($book != null)
  762.                 {                
  763.                     $translation $this->getBibleTranslationByCanonBookID($book->getId(), $nLanguageID);
  764.                     
  765.                     if(empty($translation))
  766.                         $translation $this->getBibleTranslationByUrl($book->getTranslation()->getUrl(), $nLanguageID);            }
  767.                 else
  768.                 {               
  769.                     if($nLanguageID != null)
  770.                         $translation $this->getBibleTranslationByLanguage($nLanguageID);
  771.                      else
  772.                          $translation $this->getBibleTranslationByUrl($this->DEFAULT_BIBLE_VERSION);                  
  773.                 }             
  774.             } else {
  775.                 // translation ID provided, use that                          
  776.                    $nTranslationID array_shift($columnSpec);              
  777.                    if($book != null)
  778.                    {
  779.                        $translation $this->getBibleTranslation($nTranslationID$book->getId());
  780.                        if(empty($translation))
  781.                        {
  782.                            $newbook $this->getFirstCBook($nTranslationID);
  783.                            if(!empty($newbook))
  784.                                $nNewBookID $newbook['id'];
  785.                                
  786.                            $chapterStartIndex 1;
  787.                            $chapterEndIndex=null;
  788.                            $verseStartIndex=null;
  789.                            $verseEndIndex=null;
  790.                        }
  791.                    }    
  792.                    else
  793.                        $translation $this->getBibleTranslationByID($nTranslationID);
  794.             }
  795.                           
  796.         //    $verses = DataAssembly::decanonicalizeSpan($this->getManager(), $translation['id'], $verses);       
  797.         } else {
  798.             // If not canonical, get translation from book so we know what language to use for referring Swedenborg passages
  799.             // (and so we can pass the translation to the template without having to first check whether we've defined it already)               
  800.             $nLanguageID null;
  801.             if($this->language1 !== null)
  802.                 $nLanguageID $this->language1->getId();
  803.             
  804.             if($book != null)
  805.             {
  806.                 $translation $this->getBibleTranslationByBookID($book->getId(), $nLanguageID);
  807.                 
  808.                 if(empty($translation))
  809.                     $translation $this->getBibleTranslationByUrl($book->getTranslation()->getUrl(), $nLanguageID);
  810.             }
  811.             else
  812.             {
  813.                 if($nLanguageID != null)
  814.                     $translation $this->getBibleTranslationByLanguage($nLanguageID);                    
  815.             }        
  816.         }
  817.         
  818.         $sStoryTranslationUrl null;
  819.         if($contentCategory === 'st' && isset($translation['url'])) 
  820.         {
  821.             $sStoryTranslationUrl $translation['url'];            
  822.         }
  823.         
  824.         $book2 null;        
  825.         if($book !== null) {   
  826.             if($isCanonical)    
  827.             {            
  828.                 if(!empty($translation))
  829.                     $book2 $this->bibleData('Book')->getBookFromCanon($book->getId(), $translation['id']);
  830.                 else
  831.                 {
  832.                     if($nNewBookID != null)
  833.                         $book2 $this->bibleData('Book')->getBookFromCanon($nNewBookID$nTranslationID);
  834.                 }        
  835.             }    
  836.             else
  837.                 $book2 $book;
  838.                                 
  839.             $aCheck $this->checkBookInfo($book2->getId(), $chapterStartIndex$chapterEndIndex$verseStartIndex$verseEndIndex);
  840.             if($chapterStartIndex != null && isset($aCheck['chapterStartIndex']))
  841.                 $chapterStartIndex $aCheck['chapterStartIndex'];
  842.                 
  843.             if($chapterEndIndex != null && isset($aCheck['chapterEndIndex']))
  844.                 $chapterEndIndex $aCheck['chapterEndIndex'];    
  845.                 
  846.             if($verseStartIndex != null && isset($aCheck['verseStartIndex']))
  847.                 $verseStartIndex $aCheck['verseStartIndex'];
  848.                 
  849.             if($verseEndIndex != null && isset($aCheck['verseEndIndex']))
  850.                 $verseEndIndex $aCheck['verseEndIndex'];
  851.                                                 
  852.             $verses DataAssembly::getVerseRangeFromBook($book2$chapterStartIndex$chapterEndIndex$verseStartIndex$verseEndIndex);           
  853.         } else {
  854.             $verses = array();
  855.         }
  856.         
  857.         // To switch translations, we'll use either the 'b_st_###_###' pattern (for stories),
  858.         // the 'b_cc_###_###' or 'b_cc_###-###_###' patterns (if we were given a canonical chapter specification),
  859.         // or the corresponding 'b_cv_...' patterns (if we were given canonical verses or non-canonical content).
  860.         // The "translate pattern" represents everything except the translation ID that needs to get attached to the end (to make things easier in Twig)
  861.         $translatePattern 'b_';
  862.         if($contentCategory === 'cc') {
  863.             $translatePattern .= 'cc_'.$firstChapter->getId();
  864.             if($lastChapter !== null) {
  865.                 $translatePattern .= '-'.$lastChapter->getId();
  866.             }
  867.         } elseif($contentCategory === 'st') {
  868.             if($story === null) {
  869.                 $translatePattern null;
  870.             } else {
  871.                 $translatePattern .= 'st_'.$story->getId();
  872.             }
  873.         } else {
  874.             // get IDs for first and last canonical verses, build pattern similarly
  875.             if($contentCategory === 'cv' || $contentCategory === 'st') {
  876.                 // We used canonical verses in the first place
  877.                 $firstCanonicalVerse $firstVerse;
  878.                 $lastCanonicalVerse $lastVerse;
  879.             } else {
  880.                 // We used translation-specific verses; need to find first and last canonical verses
  881.                 $canonicalVerses DataAssembly::canonicalize($verses);
  882.                 if(empty($canonicalVerses)) {
  883.                     $firstCanonicalVerse null;
  884.                     $lastCanonicalVerse null;
  885.                 } else {
  886.                     $firstCanonicalChapterVerses reset($canonicalVerses);
  887.                     $firstCanonicalVerse reset($firstCanonicalChapterVerses);
  888.                     $lastCanonicalChapterVerses end($canonicalVerses);
  889.                     $lastCanonicalVerse end($lastCanonicalChapterVerses);
  890.                 }
  891.             }
  892.             if($firstCanonicalVerse !== null) {
  893.                 $translatePattern .= 'cv_'.$firstCanonicalVerse->getId();
  894.                 if($lastCanonicalVerse !== null && $lastCanonicalVerse !== $firstCanonicalVerse) {
  895.                     $translatePattern .= '-'.$lastCanonicalVerse->getId();
  896.                 }
  897.             } else {
  898.                 // No good way to handle the case where there is no known content, but we have to do something ...
  899.                 // Setting $translatePattern to null will make it fall into the default case below
  900.                 $translatePattern null;
  901.             }
  902.         }
  903.         if($translatePattern !== null) {
  904.             $translatePattern .= '_';
  905.         } else {
  906.             // If we have too little information about the intended content to even be able to convert translations, then we'll redirect to Genesis 1
  907.          //   $gen1 = $this->bibleData('Canonical\Book')->findOneByUrl('genesis')->getChapters()->first();
  908.              $gen1 $this->getFirstCanonicalBibleChapterID('genesis');
  909.             $translatePattern 'b_cc_'.$gen1.'_';
  910.         }
  911.         $expositionRefTranslationMap = array();
  912.         $allVerses array_reduce($verses'array_merge', array());
  913.         $aVerseInfo $this->getVerseInfo($allVerses);
  914.         
  915.         $aOTLE $this->getOTLERefForBible($aVerseInfo, array(), true);                     
  916.    //     $otle_ref = $aOTLE['otle_nonmusic']; 
  917.         $otle_ref_music $aOTLE['otle_music'];
  918.         
  919.         $nChapterNum current($allVerses)->getChapter()->getOrdering();
  920.         
  921.      //   $book_list = array();
  922.         if(empty($translation) && !empty($allVerses))                    
  923.              $translation $this->getBibleTranslationByChapter(current($allVerses)->getChapter()->getId(), false);
  924.         
  925.         if (empty($translation)) {
  926.             $right_to_left False;    
  927.         } else {
  928.             $right_to_left $translation['righttoleft'];    
  929.     //        $book_list = $this->getBibleBookListForMultiColumn($translation['id']);
  930.         }
  931.                 
  932.         if($book !== null && $firstChapter !== null && $verses !== null)
  933.             $qbible_link $this->getQBibleUrl($book$firstChapter$verses$isCanonical);
  934.         
  935.         //$verseExplanations = DataAssembly::filterExplainedVerses($verses, $this->getManager());
  936.         $verseExplanations $this->getFirstExplainedVerse($aVerseInfo$request);
  937.         
  938.         $bible_column_spec '';
  939.         if($bChapterLevel || $bVerseLevel)
  940.              $bible_column_spec $columnSpec;
  941.          else
  942.          {
  943.              $bible_column_spec $this->getBibleMultiColumnSpec($translation['url'], $book->getUrl(), $chapterStartIndex$verseStartIndex$verseEndIndex);
  944.          }
  945.     
  946.         $rval = array(
  947.             'column_type' => 'bible',
  948.             'content_category' => $contentCategory,
  949.             'canonically_numbered' => $isCanonical,
  950.             'book' => $book,
  951.             'translation' => $translation,
  952.             'contents' => $verses,
  953.             'content_start_bound' => $rangeStart,
  954.             'content_end_bound' => $rangeEnd,
  955.             'translate_pattern' => $translatePattern,
  956.             'has_slider_item' => $bHasSliderItem,
  957.      //       'referring_passages' => $referringPassages,
  958.      //       'core_passages' => $corePassages,       
  959.             'verses_concept' => $this->getVerseContentWithConceptLinks($request$allVerses$bible_column_spec$column_number),
  960.             'right_to_left' => $right_to_left,       
  961.             'prev_chapter' => $prevChapter,
  962.             'next_chapter' => $nextChapter,
  963.             'prev_verse' => $prevVerse,
  964.             'next_verse' => $nextVerse,
  965.             'chapter_explanation' => $chapterExplanation,
  966.             'explained_verse' => $verseExplanations,
  967.             'qbible_link' => $qbible_link
  968.      //       'book_list' => $book_list,
  969.             'story_translation_url' => $sStoryTranslationUrl,
  970.             'chapter_id' => $nChapterId,
  971.             'verse_id' => $nVerseId,            
  972.             'otle_ref_music' => $otle_ref_music
  973.         );
  974.         
  975.         if(!empty($chapterExplanation))
  976.           {
  977.               $nTransID current($chapterExplanation)['translation_id'];
  978.               $explanation_translation $this->expositionData('Translation')->findOneById($nTransID);
  979.               
  980.               if($explanation_translation != null)
  981.               {
  982.                   $passage $explanation_translation->getWork()->findFirstNonEmptyPassage($explanation_translation);
  983.                   if($passage != null)
  984.                   {    
  985.                       $rval['explanation_text_style_override'] = $this->getTextStyleOverride($nTransID);
  986.                       $rval['explanation_translation'] = $explanation_translation;
  987.                       $rval['explanation_passage'] = $passage;
  988.                       $rval['explanation_authors'] = $this->getAuthorInfo($request$nTransID);
  989.                       $rval['explanation_text_to_speech'] = $this->getTextToSpeech($explanation_translation->getLanguage()->getId());
  990.                       $chapterData['passage_ref'] = $this->getWorkPassageRefs($passage->getId(),$nTransID$request);
  991.                       $rval['passage_multilink'] = $this->getWorkPassageMultiLink($passage->getId(),$nTransID$request);
  992.                       $rval['explanation_col1_ref'] = $this->MULTI_URL_INDICATOR_BIBLE "_" $translation['url'] . "_" $book->getUrl(). "_" $chapterStartIndex;
  993.                       $rval['explanation_col2_ref'] = $this->MULTI_URL_INDICATOR_EXPLANATION "_" $explanation_translation->getUrl();
  994.                       
  995.                       $nExplainChapterID $this->getExplainChapterID($nTransID$this->getCurrUserID($request));        
  996.                       if(!empty($nExplainChapterID))
  997.                       {
  998.                           $rval['explanation_cchapter_id'] = $nCChapterID;  
  999.                           $rval['explanation_translation_id'] = $nTransID;                      
  1000.                       }
  1001.                   }
  1002.               }    
  1003.           }
  1004.         
  1005.         if($book != null)
  1006.         {
  1007.             $nBookID null;
  1008.             if($isCanonical)
  1009.                 $nBookID $book->getId();
  1010.             else
  1011.                 $nBookID $book->getCanonicalization()->getId();    
  1012.                     
  1013.             $rval['translations_by_language'] = $this->getAllBibleTranslationsByLanguage($nBookID$nChapterNum);
  1014.             $rval['book_url'] = $book->getUrl();
  1015.             $rval['chapter_order'] = $chapterStartIndex;
  1016.             $rval['chapter_index'] = $chapterStartIndex;
  1017.         }
  1018.         if($contentCategory === 'st') {
  1019.             $rval['story'] = $story;            
  1020.             $rval['multi_story_column'] = '1';          
  1021.         } else {            
  1022.           //  $rval['verse_story'] = $this->getStoriesForVerses($aVerseInfo, $request);
  1023.         }
  1024.         if(count($verses) === 0) {
  1025.             $rval['errors'][] = array('code' => 404'message' => 'translationmismatch.bible');
  1026.         }
  1027.         
  1028.         if($translation != null)
  1029.         {            
  1030.             $msgData $this->checkBibleTranslationMsg($translation['url']); 
  1031.           if(!empty($msgData))
  1032.           {              
  1033.               $rval['contents'] = null;
  1034.               $rval['no_content_msg'] = $msgData['no_content_msg'];
  1035.           }
  1036.           
  1037.           $rval['text_style_override'] = $this->getTextStyleOverride($translation['language_id']);
  1038.           $rval['text_to_speech'] = $this->getTextToSpeech($translation['language_id']);
  1039.           $rval['translation_url'] = $translation['url'];
  1040.          } 
  1041.          
  1042.         return $rval;
  1043.     }
  1044.     protected function expositionColumnData($columnSpec$column_number$request$targetColumnNum null$renderingData null)
  1045.     {
  1046.         // Possible formats:
  1047.         // e_### (passage by id)
  1048.         // e_###_### (first number is passage id, second number is translation id)
  1049.         // e_w_### (first passage of work with given id)
  1050.         // e_t_### (first passage of translation with given id)
  1051.         // e_w_###_### (first number is id of a swedenborg work, second is section number -- use this to allow client-side generation of URLs for arbitrary Swedenborg sections)
  1052.         // e_t_###_### (as above, but first number is id of a specific translation)
  1053.         // e_xb_# (show explanation, if any, of the Bible story/verse/chapter in the specified column, e.g. e_ex_1 to show explanation)
  1054.         // e_xb_#_### (as above, but if that column doesn't show explained Bible content, then use the ExpositionTranslation whose ID is the second number)
  1055.         
  1056.         $locale $request->getLocale();
  1057.         $rval = array('column_type' => 'exposition');
  1058.         $discriminator array_shift($columnSpec);        
  1059.         $work null;
  1060.         $bSwedenborgWork false;
  1061.                 
  1062.         if($discriminator === 'w' || $discriminator === 't') {
  1063.             // Find specified work or translation
  1064.             if($discriminator === 't') {
  1065.                 $rval['lock_translation'] = true;                
  1066.                 $rval['translation'] = $this->expositionData('Translation')->findOneBy(array('id' => array_shift($columnSpec), 'isPublic' => true'type_id' => $this->TRANSLATION_TYPE_ID_TEXT));
  1067.                 if($rval['translation'] != null) {       
  1068.                     $work $rval['translation']->getWork();
  1069.                 } 
  1070.                 else
  1071.                     return array();
  1072.             } else {
  1073.                 $work $this->expositionData('Work')->findOneBy(array('id' => array_shift($columnSpec), 'isPublic' => true));
  1074.                 if($work == null)
  1075.                     return array();
  1076.                 else    
  1077.                     $rval['translation'] = $work->selectTranslation();
  1078.             }
  1079.             if(empty($columnSpec)) {
  1080.                 // No section number specified; use first passage
  1081.                 $rval['passage'] = $work->findFirstPassage();
  1082.             } else {
  1083.                 // Swedenborg section number specified
  1084.                 if($work->getSwedenborgType() === null) {
  1085.                     $rval['errors'][] = array('code' => 404'message' => 'notswedenborg');
  1086.                     return $rval;
  1087.                 }
  1088.                 $sectionNum array_shift($columnSpec);
  1089.                 $rval['passage'] = $this->expositionData('Passage')->findSwedenborgSection($work$sectionNum);
  1090.                 if($rval['passage'] === null) {
  1091.                     $rval['passage'] = (intval($sectionNum) <= 1) ? $work->findFirstPassage() : $work->findLastPassage();
  1092.                 }
  1093.             }
  1094.             
  1095.              $bSwedenborgWork = ($work->getSwedenborgType() !== null);
  1096.              if(!$bSwedenborgWork)
  1097.                 $rval['authors'] = $this->getAuthorInfo($request$rval['translation']->getId());
  1098.              else
  1099.                 $rval['IsSwedenborgWork'] = 1;    
  1100.         } elseif($discriminator === 'xb') {
  1101.             $dependentColumnNum array_shift($columnSpec);
  1102.             if($renderingData === null) {
  1103.                 // Start by listing no dependencies, then add a dependency for the appropriate column
  1104.                 // (this way we don't have to make sure not to set the wrong dependency to 'none')
  1105.                 $dependencies = array(=> 'none'=> 'none'=> 'none');
  1106.                 if(!array_key_exists($dependentColumnNum$dependencies)) {
  1107.                     throw $this->createNotFoundException('Invalid column specification: Dependency on nonexistent column number "'.$dependentColumnNum.'"');
  1108.                 }
  1109.                 $dependencies[$dependentColumnNum] = empty($columnSpec) ? 'required' 'optional';
  1110.                 return array('column_type' => 'dependent''depends_on' => $dependencies'final_column_type' => 'exposition');
  1111.             }
  1112.             if(!array_key_exists($dependentColumnNum$renderingData['columns'])) {
  1113.                 throw new \Exception('Invalid column specification: Dependency on unavailable column number "'.$dependentColumnNum.'"');
  1114.             }
  1115.             $dependentColumnData $renderingData['columns'][$dependentColumnNum];
  1116.             if($dependentColumnData['column_type'] !== 'bible') {
  1117.                 // If the column this depends on doesn't have Bible content, then we need a fallback in order to display anything
  1118.                 if(empty($columnSpec)) {
  1119.                     throw $this->createNotFoundException('Invalid column specification: Target column does not contain required content type');
  1120.                 }
  1121.                 $fallbackId array_shift($columnSpec);
  1122.                 $rval['translation'] = $this->expositionData('Translation')->findOneBy(array('id' => $fallbackId'isPublic' => true'type_id' => $this->TRANSLATION_TYPE_ID_TEXT));
  1123.                 if($rval['translation'] == null) {
  1124.                     $rval['errors'][] = array('code' => 404'message' => 'generic.alert.404');
  1125.                     return $rval;
  1126.                 }
  1127.                 else
  1128.                 {
  1129.                     $work $rval['translation']->getWork();
  1130.                     $rval['passage'] = $work->findFirstPassage();
  1131.                     $rval['lock_translation'] = true;                
  1132.                     $rval['authors'] = $this->getAuthorInfo($request$rval['translation']->getId());      
  1133.                 }             
  1134.                 return $rval;
  1135.             }
  1136.             $explanationOptions = array();
  1137.             $firstExplanationID null;
  1138.             if(isset($dependentColumnData['story'])) {
  1139.                 $explanationOptions $dependentColumnData['story']->getExplanations()->toArray();
  1140.                 $firstExplanationID $this->getFirstExplanationID($dependentColumnData['story']->getId());
  1141.             } elseif(array_key_exists('story'$dependentColumnData)) {
  1142.                 // Should happen if a nonexistent story is requested
  1143.                 $explanationOptions = array();
  1144.             } else {
  1145.                 // Try to find a Story entity associated with the content being displayed (most likely a verse or chapter?)
  1146.                 $bibleContent $dependentColumnData['contents'];
  1147.                 $firstBibleChapterContents reset($bibleContent);
  1148.                 $firstBibleVerse $firstBibleChapterContents reset($firstBibleChapterContents) : null;
  1149.                 if(count($bibleContent) === && count($firstBibleChapterContents) === 1) {
  1150.                     $verseStories DataAssembly::findVerseStories($firstBibleVerse$this->getManager());
  1151.                     foreach($verseStories as $story) {
  1152.                         $explanationOptions array_merge($explanationOptions$story->getExplanations()->toArray());
  1153.                     }
  1154.                 } else {
  1155.                     // TODO: If we're showing a whole chapter, then we should show chapter explanations once we have them
  1156.                     // TODO: If the text we're showing happens to line up exactly with a story, then we should show an explanation for that story
  1157.                 }
  1158.             }
  1159.             if(empty($explanationOptions)) {
  1160.                 // If no explanation available, show fallback content; if no fallback, show "no explanation available" message
  1161.                 if(empty($columnSpec)) {
  1162.                     $rval['errors'][] = array('code' => 404'message' => 'noexplanation');
  1163.                     return $rval;
  1164.                 }
  1165.                 $fallbackId array_shift($columnSpec);
  1166.                 $rval['translation'] = $this->expositionData('Translation')->findOneBy(array('id' => $fallbackId'isPublic' => true'type_id' => $this->TRANSLATION_TYPE_ID_TEXT));
  1167.                 if($rval['translation'] == null) {
  1168.                     $rval['errors'][] = array('code' => 404'message' => 'generic.alert.404');
  1169.                     return $rval;
  1170.                 }
  1171.                 else
  1172.                 {
  1173.                     $work $rval['translation']->getWork();
  1174.                     $rval['passage'] = $work->findFirstPassage();
  1175.                     $rval['lock_translation'] = true;                
  1176.                     $rval['authors'] = $this->getAuthorInfo($request$rval['translation']->getId());      
  1177.                 }
  1178.                           
  1179.                 return $rval;
  1180.             } else {
  1181.                 $explanation $this->getFirstExplanation($explanationOptions$firstExplanationID);
  1182.                 $rval['passage'] = $explanation->findFirstPassage();
  1183.                 $rval['translation'] = $explanation->selectTranslation();
  1184.                 if($rval['translation'] == null) {
  1185.                     $rval['errors'][] = array('code' => 404'message' => 'generic.alert.404');
  1186.                     return $rval;
  1187.                 }
  1188.                 else
  1189.                 {
  1190.                     $rval['column_uri_override'] = 'e_xb_'.$dependentColumnNum.'_'.$rval['translation']->getId();
  1191.                     $rval['authors'] = $this->getAuthorInfo($request$rval['translation']->getId());
  1192.                 }    
  1193.             }
  1194.                 
  1195.         } else { // $discriminator isn't 'w' or 't' or 'xb'
  1196.             // We should normally be able to reach this point only if $discriminator is a numeral
  1197.             $rval['passage'] = $this->expositionData('Passage')->findOneById($discriminator);
  1198.             if($rval['passage'] == null) {
  1199.                 $rval['errors'][] = array('code' => 404'message' => 'generic.alert.404');
  1200.                 return $rval;
  1201.             }
  1202.             
  1203.             if(empty($columnSpec)) {
  1204.                 $work $rval['passage']->findWork();
  1205.                 $rval['translation'] = $work->selectTranslation();
  1206.             } else {
  1207.             
  1208.                 $rval['lock_translation'] = true;
  1209.                 $rval['translation'] = $this->expositionData('Translation')->findOneById(array_shift($columnSpec));
  1210.                 if($rval['translation'] == null) {
  1211.                     $rval['errors'][] = array('code' => 404'message' => 'generic.alert.404');
  1212.                     return $rval;
  1213.                 }
  1214.                 
  1215.                 if($rval['translation']->getWork() != $rval['passage']->findWork()) {
  1216.                     $rval['errors'][] = array('code' => 404'message' => 'translationmismatch.exposition');
  1217.                     return $rval;
  1218.                 }
  1219.                 else
  1220.                     $work $rval['passage']->findWork();
  1221.             }   
  1222.                                     
  1223.             if($work != null)
  1224.             {
  1225.                 $bSwedenborgWork = ($work->getSwedenborgType() !== null);
  1226.                 if(!$bSwedenborgWork)
  1227.                     $rval['authors'] = $this->getAuthorInfo($request$rval['translation']->getId());
  1228.                 else
  1229.                     $rval['IsSwedenborgWork'] = 1;
  1230.             }                                 
  1231.         }
  1232.                                 
  1233.         $bCheckTrans = ($this->language1 == null);
  1234.         if($bCheckTrans)
  1235.         {
  1236.             $this->language1 $rval['translation']->getLanguage();
  1237.             $this->work1 $work;
  1238.         }
  1239.                         
  1240.         if($work !== null && !$bSwedenborgWork) {
  1241.             // get concept illustrations
  1242.             $sConceptUrl $this->getConceptUrl($work->getId());            
  1243.             if($sConceptUrl != '')
  1244.             {
  1245.                 $sWorkUrl $work->getUrl();
  1246.                 $concept $this->getRepository('Concepts\Concept')->findOneByUrl($sWorkUrl);
  1247.                 if($concept !== null) {
  1248.                     $illustrations $concept->getIllustrations();    
  1249.                     $rval['image'] = ($illustrations->isEmpty()) ? null $illustrations[0]->getImage();
  1250.                 }
  1251.             }
  1252.             
  1253.             $bConsider false;
  1254.             $bBibleStudy false;            
  1255.             foreach($work->getCategories() as $category) {
  1256.                 if($category->getId() == 13) {
  1257.                     $bConsider true;
  1258.                 }
  1259.                 
  1260.                 if($category->getId() == 14) {
  1261.                     $bBibleStudy true;
  1262.                 }
  1263.             }           
  1264.             
  1265.             if($bConsider)
  1266.             {
  1267.                 $rval['consider_data'] = $this->getConsiderList($locale);
  1268.             }
  1269.             
  1270.             if($bBibleStudy)
  1271.             {
  1272.                 $rval['biblestudy_data'] = $this->getBibleStudyList($locale);
  1273.             }
  1274.         }
  1275.     
  1276.         if($rval['translation'] != null)
  1277.         {
  1278.             $nLanguageID $rval['translation']->getLanguage()->getId();
  1279.             $rval['text_style_override'] = $this->getTextStyleOverride($nLanguageID);            
  1280.             
  1281.             $ref_column_spec '';
  1282.             if($rval['translation']->getWork()->getSwedenborgType() !== null)
  1283.                 $ref_column_spec $this->MULTI_URL_INDICATOR_SWEDENBORG_WORK;    
  1284.             else
  1285.                 $ref_column_spec $this->MULTI_URL_INDICATOR_EXPLANATION;    
  1286.             
  1287.             $ref_column_spec .= '_' $rval['translation']->getUrl();
  1288.             if(isset($rval['passage']) && $rval['passage'] != null && $rval['translation']->getWork()->getSwedenborgType() !== null)
  1289.                 $ref_column_spec .= '_' $rval['passage']->getSwedenborgSection();
  1290.                 
  1291.             $rval['ref_column_spec'] = $ref_column_spec;
  1292.             $rval['text_to_speech'] = $this->getTextToSpeech($nLanguageID);
  1293.             $rval['translation_url'] = $rval['translation']->getUrl();
  1294.         }
  1295.     
  1296.         if($rval['translation'] != null && $rval['passage'] != null)
  1297.         {
  1298.             $rval['previous_passage'] = $this->getPreviousPassageWithContent($rval['passage'], $rval['translation']);
  1299.                        
  1300.             $rval['next_passage'] = $this->getNextPassageWithContent($rval['passage'], $rval['translation']);
  1301.                             
  1302.             if($bSwedenborgWork)
  1303.                 $rval['related_bible_ref'] = $this->getRelatedBibleRefForWork($rval['passage']->getId(),$rval['translation']->getId(), $request);    
  1304.             else
  1305.                 $rval['passage_ref'] = $this->getWorkPassageRefs($rval['passage']->getId(),$rval['translation']->getId(), $request);    
  1306.                 
  1307.             $rval['passage_footnote'] = $this->getPassageFootnotes($rval['passage']->getId(),$rval['translation']->getId());
  1308.             $rval['passage_multilink'] = $this->getWorkPassageMultiLink($rval['passage']->getId(),$rval['translation']->getId(), $request);
  1309.             if($rval['translation']->getLanguage()->getId() == $this->LANGUAGE_ID_LATIN)
  1310.             {                
  1311.                 $rval['passage_scanimage'] = $this->getWorkPassageScanImageFileName($rval['passage']->getId());
  1312.                 $rval['define_latin_icon'] = 1;
  1313.             }
  1314.         }        
  1315.                                 
  1316.         return $rval;
  1317.     }
  1318.     public function storyExplanationAction($storyUrlRequest $request$bibleTranslationUrl null$commentaryUrl null)
  1319.     {
  1320.         $locale $request->getLocale();
  1321.         $response null;
  1322.         $story $this->bibleData('Stories\Story')->findOneBy(array('url' =>$storyUrl'level_id' => $this->STORY_LEVEL_ID_BIBLE'isPublic' => true)); 
  1323.         if($story==null)
  1324.         {
  1325.             $response = new Response();
  1326.             $response->setStatusCode(404);
  1327.             return $this->renderView('no_content_back', array(), $response);
  1328.         }       
  1329.                 
  1330.         if($locale != 'en')
  1331.         {
  1332.             $sStoryName $this->getBibleStoryName($story->getId(), $locale); 
  1333.             if(!empty($sStoryName))
  1334.                 $story->setName($sStoryName);
  1335.         }  
  1336.         
  1337.         $sCommentaryUrl $commentaryUrl;
  1338.         if($sCommentaryUrl == null)
  1339.         {
  1340.             $sCommentaryUrl $this->getCommentaryUrl($story->getId(), $bibleTranslationUrl);
  1341.         }
  1342.         else
  1343.         {
  1344.             $sCommentaryUrl $this->getPublicCommentaryUrl($story->getId(), $commentaryUrl);
  1345.         }    
  1346.         
  1347.         if($sCommentaryUrl == '')
  1348.         {
  1349.             $response = new Response();
  1350.             $response->setStatusCode(404);
  1351.             return $this->renderView('no_content_back', array(), $response);
  1352.         }
  1353.                                           
  1354.         $renderingData = array('route_story' => $story);        
  1355.         $renderingData['commentary_url_from_link'] = $commentaryUrl;
  1356.                 
  1357.         $storySpec $this->MULTI_URL_INDICATOR_BIBLE_STORYTEXT '_' $story->getUrl();
  1358.         $renderingData['right_to_left'] = False;
  1359.         if($bibleTranslationUrl !== null) {
  1360.         
  1361.             if($bibleTranslationUrl !== $this->DEFAULT_BIBLE_VERSION)
  1362.             {
  1363.                 // check bible translation match
  1364.                 $bHasBibleBookForTrans $this->HasBibleBookForTrans($story->getId(), $bibleTranslationUrl);
  1365.                 if(!$bHasBibleBookForTrans)
  1366.                 {
  1367.                     $bibleTranslationUrl $this->DEFAULT_BIBLE_VERSION;
  1368.                     if($commentaryUrl != null)
  1369.                     {
  1370.                         return $this->redirect($this->get('router')->generate('bible_translated_story_for_commentary', array(
  1371.                             'storyUrl' => $storyUrl,
  1372.                             'bibleTranslationUrl' => $bibleTranslationUrl,
  1373.                             'commentaryUrl' => $commentaryUrl
  1374.                         )), 301);
  1375.                     }
  1376.                     else 
  1377.                     { 
  1378.                         return $this->redirect($this->get('router')->generate('bible_translated_story', array(
  1379.                             'storyUrl' => $storyUrl,
  1380.                             'bibleTranslationUrl' => $bibleTranslationUrl
  1381.                         )), 301);
  1382.                     }
  1383.                 }
  1384.             }
  1385.         
  1386.             $bibleTranslation $this->bibleData('Translation')->findOneBy(array('url' => $bibleTranslationUrl'enabled' => true));
  1387.             
  1388.             if($bibleTranslation !== null)
  1389.             {
  1390.                 $renderingData['route_bible_translation'] = $bibleTranslation;
  1391.                 $storySpec .= '_'.$bibleTranslation->getUrl();
  1392.                 $renderingData['right_to_left'] = $bibleTranslation->getLanguage()->getRightToLeft();  
  1393.             }                 
  1394.         }
  1395.                 
  1396.         $renderingData['content_class'] = 'story';
  1397.         
  1398.         $explanationSpec $this->MULTI_URL_INDICATOR_EXPLANATION '_' $sCommentaryUrl;
  1399.         $this->setCurrentUrl($request);         
  1400.         return $this->multicolumnAction($storySpec$explanationSpec$requestnull$renderingData);
  1401.     }
  1402.     
  1403.     public function showExceptionAction()
  1404.     {        
  1405.         return $this->renderView('no_content', array(), $response);
  1406.     }
  1407.     
  1408.     public function storyRedirectAction($storyUrlRequest $request)
  1409.     {
  1410.         $bibleTranslationUrl $this->DEFAULT_BIBLE_VERSION;
  1411.         $nBibleTransID $request->getSession()->get('current_bible_translation_id');
  1412.         if($nBibleTransID != '')
  1413.         {
  1414.    //         $bibleTranslation = $this->getRepository('Bible\Translation')->findOneById($nBibleTransID);
  1415.    //         $bibleTranslationUrl = $bibleTranslation->getUrl();
  1416.    
  1417.                $bibleTranslation $this->getBibleTranslationByID($nBibleTransID);
  1418.                $bibleTranslationUrl $bibleTranslation['url'];
  1419.         }
  1420.         
  1421.         return $this->redirect($this->get('router')->generate('bible_translated_story', array(
  1422.                     'storyUrl' => $storyUrl,
  1423.                     'bibleTranslationUrl' => $bibleTranslationUrl
  1424.                 )), 301);
  1425.         //return $this->redirect('/bible/story/'.$storyUrl.'/'.$bibleTranslationUrl);
  1426.     }
  1427.     
  1428.     // Anytime you are reading content that has a link to other content, if available, 
  1429.     // link to a translation of the new content in the same language as the content that links to it. 
  1430.     public function checkBibleTranslation($vTranslation$vLanguage)
  1431.     {        
  1432.         $ret $this->bibleData('Translation')->findOneBy(array('language' => $vLanguage'enabled'=> true'languageDefault' => true));
  1433.         if($ret == null)
  1434.             $ret $this->bibleData('Translation')->findOneBy(array('language' => $vLanguage'enabled' => true));
  1435.                             
  1436.         return $ret;        
  1437.     }     
  1438.     
  1439.     function getQBibleUrl($book$chapter$verses$isCanonical)
  1440.     {
  1441.         if($isCanonical)
  1442.             $cbook $book;
  1443.         else
  1444.             $cbook $book->getCanonicalization();
  1445.                         
  1446.         $nCBookId $cbook->getId();
  1447.         $nChapterOrder $chapter->getOrdering();
  1448.         $nVerseOrder 1;
  1449.         foreach($verses as $key => $val) {
  1450.             if(!is_array($val)) {
  1451.                 $nVerseOrder $val->getIndexDisplay();  
  1452.                 break;              
  1453.             }
  1454.         }
  1455.                        
  1456.         $nTestmentId $cbook->getTestament()->getId();
  1457.         $sLinkStart '';
  1458.         if($nTestmentId == 1// old testament
  1459.             $sLinkStart 'http://qbible.com/hebrew-old-testament/';
  1460.         else
  1461.             $sLinkStart 'http://qbible.com/greek-new-testament/';    
  1462.     
  1463.         return $this->getNativeQueryResults("SELECT '" $sLinkStart "' || qbible_url || '/' || '" $nChapterOrder "' || '.html#' || '" $nVerseOrder "' as url from canonicalbiblebook"                
  1464.                 ." WHERE id = " $nCBookId " and qbible_url is not null and qbible_url <> ''");
  1465.     } 
  1466.     
  1467.     function getFirstExplanationID($story_id)
  1468.     {        
  1469.         $sSql "SELECT work_id"
  1470.                 ." FROM story_work"
  1471.                 ." WHERE story_id = " $story_id " order by ordering";
  1472.         $sRet '';
  1473.         $aRet $this->getNativeQueryResults($sSql);
  1474.         if(count($aRet) > 0
  1475.             $sRet implode(''$aRet[0]);        
  1476.               
  1477.         return $sRet;    
  1478.     }  
  1479.     
  1480.     function getFirstExplanation($explanationOptions$firstExplanationID)
  1481.     {
  1482.         $firstExplanation null;
  1483.         foreach($explanationOptions as $expanation)
  1484.         {
  1485.             if($expanation->getId() == $firstExplanationID)
  1486.             {
  1487.                 $firstExplanation $expanation;
  1488.                 break;
  1489.             }
  1490.         }
  1491.         
  1492.         if($firstExplanation == null)
  1493.             $firstExplanation $explanationOptions[0];
  1494.             
  1495.         return $firstExplanation;    
  1496.     }
  1497.     
  1498.     protected function bibleColumnDataNew($columnDetails$column_number$request$targetColumnNum null$renderingData null)
  1499.     {
  1500.         // Old Possible formats:
  1501.         // b_c_### (chapter by id)
  1502.         // b_c_###-### (chapter range by ids)
  1503.         // b_v_### (verse by ids)
  1504.         // b_v_###-### (verse range by ids, possibly spanning multiple chapters)
  1505.         // To use canonical numbering, replace "c" with "cc" or "v" with "cv" in the above
  1506.         // b_st_### (bible text for the story with the given id)
  1507.         // Canonical-numbered content (including stories) will use default or arbitrary translation; adding "_###" to the end specifies the translation ID
  1508.         
  1509.         // e.g. bible_king-james-version_genesis_1_2
  1510.         
  1511.         $dataElementDetails explode('_'strtolower($columnDetails));
  1512.         $domainIndicator array_shift($dataElementDetails);
  1513.         $columnSpec $dataElementDetails;                   
  1514.                 
  1515. //echo 'ttt1:'.time(); 
  1516.         $chapterExplanation null;
  1517.         $qbible_link null;
  1518.         $verses null;
  1519.         $translation = array();
  1520.         $nChapterId null;
  1521.         $nLastChapterId null;
  1522.         $nVerseId null;
  1523.         $isCanonical false;                
  1524.         $nextChapter null;
  1525.           $prevChapter null;
  1526.           $nextVerse null;
  1527.           $prevVerse null;  
  1528.           
  1529.           $nSpecCount count($columnSpec);        
  1530.         $bChapterLevel false;
  1531.         $bVerseLevel false;
  1532.         $bStoryText = ($domainIndicator === $this->MULTI_URL_INDICATOR_BIBLE_STORYTEXT);
  1533.         $aChapter = array();
  1534.         $aVerse = array();
  1535.         $nChapterNum null;
  1536.         $nLastChapterNum null;
  1537.         $sVerseIndex null;
  1538.         $sLastVerseIndex null;
  1539.         $sTranslationUrl null;
  1540.         $firstChapter null;
  1541.           
  1542.           if(!$bStoryText)
  1543.         {                  
  1544.             $bChapterLevel = ($nSpecCount == 3);
  1545.             $bVerseLevel = ($nSpecCount == 4);        
  1546.             $sTranslationUrl array_shift($columnSpec);            
  1547.             $sBookUrl array_shift($columnSpec);
  1548.             $sChapterStr array_shift($columnSpec);
  1549.             $aChapter explode('-'$sChapterStr);
  1550.             $nChapterNum $aChapter[0];
  1551.             if(count($aChapter) > 1)
  1552.             {
  1553.                 $nLastChapterNum $aChapter[1];
  1554.                 if ( $nLastChapterNum $nChapterNum >= 
  1555.                       $nLastChapterNum $nChapterNum+2;
  1556.             }    
  1557.                 
  1558.             $nChapterIDCount count($aChapter);
  1559.             if($bVerseLevel)
  1560.             {
  1561.                 $sVerseStr array_shift($columnSpec);    
  1562.                 $aVerse explode('-'$sVerseStr);
  1563.                 $nVerseIDCount count($aVerse);
  1564.                 $sVerseIndex $aVerse[0];
  1565.                 if($nVerseIDCount 1)
  1566.                     $sLastVerseIndex $aVerse[1];
  1567.             }     
  1568.             
  1569.             $nChapterId $this->getBibleChapterID($sTranslationUrl$sBookUrl$nChapterNum);      
  1570.             if($nLastChapterNum != null)
  1571.                 $nLastChapterId $this->getBibleChapterID($sTranslationUrl$sBookUrl$nLastChapterNum);
  1572.             
  1573.             if($nChapterId == null)
  1574.             {
  1575.                 $nChapterNum 1;
  1576.                 $bChapterLevel true;
  1577.                 $nChapterId $this->getBibleChapterID($sTranslationUrl$sBookUrl$nChapterNum); 
  1578.             }
  1579.             
  1580.             if($nChapterId == null)
  1581.                 return array();
  1582.                  
  1583.               $translation $this->getBibleTranslationByChapter($nChapterId$isCanonical);       
  1584.         }
  1585.         else
  1586.         {
  1587.             $sStoryUrl array_shift($columnSpec);
  1588.             $sTranslationUrl array_shift($columnSpec);
  1589.         }
  1590.         
  1591.         $contentCategory '';
  1592.         if($bStoryText)
  1593.             $contentCategory 'st';
  1594.         else if ($bChapterLevel)
  1595.             $contentCategory 'c';
  1596.         else
  1597.             $contentCategory 'v';    
  1598.                   
  1599.         if($bChapterLevel) {  
  1600.             $chapterRepos $this->bibleData($isCanonical 'Canonical\Chapter' 'Chapter');
  1601.             $firstChapter $chapterRepos->findOneById($nChapterId);
  1602.             $lastChapter null;
  1603.             $chapterEndIndex null;
  1604.             if($firstChapter !== null) {
  1605.                 $book $firstChapter->getBook();
  1606.                 $chapterStartIndex $firstChapter->getOrdering();
  1607.                 if($nChapterIDCount == || !empty($nLastChapterId)) {
  1608.                     $lastChapter null;
  1609.                     $chapterEndIndex null;
  1610.                 } else {
  1611.                 //    $nLastChapterNum = $aChapter[1];
  1612.                 //    $nLastChapterId = $this->getBibleChapterID($sTranslationUrl, $sBookUrl, $nLastChapterNum);
  1613.                     if(!empty($nLastChapterId))
  1614.                     {
  1615.                         $lastChapter $chapterRepos->findOneById($nLastChapterId);
  1616.                         $chapterEndIndex $lastChapter->getOrdering();
  1617.                     }                    
  1618.                 }
  1619.             } else {
  1620.                 $book null;
  1621.                 $lastChapter null;
  1622.                 $chapterStartIndex null;
  1623.                 $chapterEndIndex null;
  1624.             }
  1625.             $verseStartIndex null;
  1626.             $verseEndIndex null;
  1627.             $rangeStart $firstChapter;
  1628.             $rangeEnd $lastChapter
  1629.             
  1630.             if($chapterExplanation == null && !empty($translation))
  1631.             {            
  1632.                 // get chapter explanation                    
  1633.                 $chapterExplanation $this->getChapterExplanation($translation['chapter_id'], $sTranslationUrl$request); 
  1634.                 $nextChapter $this->getNextChapter($nChapterId);
  1635.                   $prevChapter $this->getPreviousChapter($nChapterId);
  1636.             }
  1637.             
  1638.             $nCChapterID null;
  1639.             if($isCanonical)
  1640.                 $nCChapterID $firstChapter->getId();
  1641.             else
  1642.             {
  1643.                 $cchapter $firstChapter->getCanonicalization();
  1644.                 if($cchapter != null)
  1645.                     $nCChapterID $cchapter->getId();    
  1646.             }            
  1647.             // It's very slow, we will find a better way to do it
  1648.              $nExplainChapterTranslationID $this->getExplainChapterTranslation($nCChapterID$this->getCurrUserID($request), $sTranslationUrl);            
  1649.               if($nExplainChapterTranslationID > -1)
  1650.               {                  
  1651.                   if($request->getSession()->get('has_explanation_cchapter_id_temp_bible') == '1')
  1652.                 {
  1653.                     // For multi-column views, explain chapter icon is not shown 
  1654.                     // if there are more than 1 chapter column
  1655.                     $request->getSession()->set('current_explanation_cchapter_id_temp_bible''');
  1656.                     $request->getSession()->set('current_explanation_translation_id_temp_bible''');                   
  1657.                 }
  1658.                 else
  1659.                 {
  1660.                     $request->getSession()->set('has_explanation_cchapter_id_temp_bible''1'); 
  1661.                     $request->getSession()->set('current_explanation_cchapter_id_temp_bible'$nCChapterID); 
  1662.                       $request->getSession()->set('current_explanation_translation_id_temp_bible'$nExplainChapterTranslationID);  
  1663.                 }       
  1664.               }       
  1665.         } else {
  1666.             if($bStoryText) {    
  1667.                 $isCanonical true;                        
  1668.                 if(empty($sStoryUrl)) {
  1669.                     $story null;
  1670.                     $firstVerse null;
  1671.                     $lastVerse null;
  1672.                 } else {
  1673.                     $story $this->bibleData('Stories\Story')->findOneBy(array('url' => $sStoryUrl'level_id' => $this->STORY_LEVEL_ID_BIBLE'isPublic' => true));
  1674.                     if($story === null) {
  1675.                         $firstVerse null;
  1676.                         $lastVerse null;
  1677.                     } else {
  1678.                         $firstVerse $story->getStartVerse();
  1679.                         $lastVerse $story->getEndVerse();  
  1680.                         
  1681.                         if($chapterExplanation == null && $firstVerse !== null)
  1682.                         {                     
  1683.                             $firstChapter $firstVerse->getChapter(); 
  1684.                             $CChapter $firstChapter;
  1685.                             if($CChapter != null)
  1686.                             {
  1687.                                 $nChapterId $CChapter->getId();
  1688.                                 $chapterExplanation $this->getChapterExplanation($nChapterId$sTranslationUrl$request);
  1689.                             }
  1690.                             $nextChapter $this->getNextChapter($firstChapter->getId());
  1691.                               $prevChapter $this->getPreviousChapter($firstChapter->getId());
  1692.                         }                
  1693.                     }
  1694.                 }
  1695.             } else {            
  1696.                 $verseRepos $this->bibleData($isCanonical 'Canonical\Verse' 'Verse');
  1697.                 $nVerseId $this->getBibleVerseID($sTranslationUrl$sBookUrl$nChapterNum$sVerseIndex); 
  1698.                   if($nVerseId == null)
  1699.                   {
  1700.                       $sTranslationUrl $this->DEFAULT_BIBLE_VERSION;
  1701.                       $nVerseId $this->getBibleVerseID($sTranslationUrl$sBookUrl$nChapterNum$sVerseIndex);
  1702.                   }    
  1703.                            
  1704.                 $firstVerse $verseRepos->findOneById($nVerseId);
  1705.                 
  1706.                 $lastVerse null;
  1707.                 if($sLastVerseIndex != null)
  1708.                 {
  1709.                     if($nLastChapterNum != null)
  1710.                         $nLastVerseId $this->getBibleVerseID($sTranslationUrl$sBookUrl$nLastChapterNum$sLastVerseIndex);
  1711.                     else
  1712.                         $nLastVerseId $this->getBibleVerseID($sTranslationUrl$sBookUrl$nChapterNum$sLastVerseIndex);
  1713.                             
  1714.                     $lastVerse $verseRepos->findOneById($nLastVerseId);
  1715.                 }
  1716.                 if(!$isCanonical) {
  1717.                     if($firstVerse !== null) {
  1718.                         $firstVerse $firstVerse->findMainVerse();
  1719.                     }
  1720.                     if($lastVerse !== null) {
  1721.                         $lastVerse $lastVerse->findMainVerse();
  1722.                     }                                        
  1723.              
  1724.                     if($chapterExplanation == null && $firstVerse !== null)
  1725.                     {                     
  1726.                         $firstChapter $firstVerse->getChapter(); 
  1727.                         $CChapter $firstChapter->getCanonicalization();
  1728.                         if($CChapter != null)
  1729.                         {
  1730.                             $nChapterId $CChapter->getId();
  1731.                             $chapterExplanation $this->getChapterExplanation($nChapterId$sTranslationUrl$request);
  1732.                         }
  1733.                         $nextChapter $this->getNextChapter($firstChapter->getId());
  1734.                           $prevChapter $this->getPreviousChapter($firstChapter->getId());
  1735.                     }                        
  1736.                 }     
  1737.                 
  1738.                 if($nVerseId != null && $nVerseId != '')
  1739.                 {
  1740.                     $nextVerse $this->getNextVerse($nVerseId);
  1741.                       $prevVerse $this->getPreviousVerse($nVerseId); 
  1742.                   }          
  1743.             }
  1744.             if($firstVerse !== null) {
  1745.                 $firstChapter $firstVerse->getChapter();
  1746.                 $book $firstChapter->getBook();
  1747.                 $chapterStartIndex $firstChapter->getOrdering();                                
  1748.                 $verseStartIndex $contentCategory === 'v' $firstVerse->getIndexDisplay() : $firstVerse->getOrdering();
  1749.                 if($lastVerse === null) {
  1750.                     $chapterEndIndex null;
  1751.                     $verseEndIndex null;
  1752.                 } else {
  1753.                     $chapterEndIndex $lastVerse->getChapter()->getOrdering();
  1754.                     $verseEndIndex $contentCategory === 'v' $lastVerse->getIndexDisplay() : $lastVerse->getOrdering();
  1755.                 }
  1756.             } else {
  1757.                 $book null;
  1758.                 $chapterStartIndex null;
  1759.                 $verseStartIndex null;
  1760.                 $chapterEndIndex null;
  1761.                 $verseEndIndex null;
  1762.             }
  1763.             $rangeStart $firstVerse;
  1764.             $rangeEnd $lastVerse;            
  1765.         }
  1766.         
  1767.         if($bStoryText) { 
  1768.             if($sTranslationUrl == null) {
  1769.                 // default or arbitrary translation
  1770.                 // TODO: Select language-default translation for current or default language, or use last viewed translation
  1771.                 $nLanguageID null;
  1772.                 if($this->language1 !== null)
  1773.                     $nLanguageID $this->language1->getId();
  1774.                                      
  1775.                 if($book != null)
  1776.                 {
  1777.                     $translation $this->getBibleTranslationByCanonBookID($book->getId(), $nLanguageID);
  1778.                     
  1779.                     if(empty($translation))
  1780.                         $translation $this->getBibleTranslationByUrl($book->getTranslation()->getUrl(), $nLanguageID);        }
  1781.                 else
  1782.                 {
  1783.                     if($nLanguageID != null)
  1784.                         $translation $this->getBibleTranslationByLanguage($nLanguageID);
  1785.                      else
  1786.                          $translation $this->getBibleTranslationByUrl($this->DEFAULT_BIBLE_VERSION);                  
  1787.                 }             
  1788.             } else {
  1789.                 // translation ID provided, use that    
  1790.                    $translation $this->getBibleTranslationByUrl($sTranslationUrl);
  1791.             }
  1792.             
  1793.             if($sTranslationUrl == '')
  1794.             {                 
  1795.                 $sTranslationUrl $translation['url'];
  1796.             }
  1797.       } 
  1798.       else
  1799.       {          
  1800.         // If not canonical, get translation from book so we know what language to use for referring Swedenborg passages
  1801.         // (and so we can pass the translation to the template without having to first check whether we've defined it already)               
  1802.         
  1803.         if($sTranslationUrl != '')
  1804.             $translation $this->getBibleTranslationByUrl($sTranslationUrl); 
  1805.      }
  1806.      
  1807.          $sStoryTranslationUrl null;
  1808.         if($bStoryText && isset($translation['url'])) 
  1809.         {
  1810.             $sStoryTranslationUrl $translation['url'];            
  1811.         }
  1812.          
  1813.         $curr_book null;        
  1814.         if($book !== null) {   
  1815.             if($isCanonical)  
  1816.             {       
  1817.                 $book2 null;
  1818.                 if(!empty($translation) && isset($translation['id']))                  
  1819.                     $book2 $this->bibleData('Book')->getBookFromCanon($book->getId(), $translation['id']);
  1820.                     
  1821.                 if($book2 == null)
  1822.                 {
  1823.                     $book2 $this->bibleData('Book')->getBookFromCanon($book->getId(), $this->DEFAULT_BIBLE_TRANSLATION_ID);                    
  1824.                     $sTranslationUrl $this->DEFAULT_BIBLE_VERSION;
  1825.                     $translation $this->getBibleTranslationByUrl($sTranslationUrl);
  1826.                 }    
  1827.             }    
  1828.             else
  1829.                 $book2 $book;
  1830.                 
  1831.             $curr_book $book2;    
  1832.           
  1833.             $aCheck $this->checkBookInfo($book2->getId(), $chapterStartIndex$chapterEndIndex$verseStartIndex$verseEndIndex);
  1834.             if($chapterStartIndex != null && isset($aCheck['chapterStartIndex']))
  1835.                 $chapterStartIndex $aCheck['chapterStartIndex'];
  1836.                 
  1837.             if($chapterEndIndex != null && isset($aCheck['chapterEndIndex']))
  1838.                 $chapterEndIndex $aCheck['chapterEndIndex'];    
  1839.                 
  1840.             if($verseStartIndex != null && isset($aCheck['verseStartIndex']))
  1841.                 $verseStartIndex $aCheck['verseStartIndex'];
  1842.                 
  1843.             if($verseEndIndex != null && isset($aCheck['verseEndIndex']))
  1844.                 $verseEndIndex $aCheck['verseEndIndex']; 
  1845.                  
  1846.             $verses DataAssembly::getVerseRangeFromBook($book2$chapterStartIndex$chapterEndIndex$verseStartIndex$verseEndIndex);           
  1847.         } else {
  1848.           //  $verses = array();
  1849.             return array();
  1850.         }
  1851.                 
  1852.         $expositionRefTranslationMap = array();
  1853.         $allVerses array_reduce($verses'array_merge', array());
  1854.         
  1855.         $aTempChapter = array();
  1856.         if($bChapterLevel)        
  1857.             $aTempChapter[] = $firstChapter;
  1858.         $aVerseInfo $this->getVerseInfo($allVerses);   
  1859.         $bHasSliderItem $this->hasSliderItem($aVerseInfofalse$requesttrue);
  1860.         if($bHasSliderItem)
  1861.         {
  1862.             $sSliderUrl "";
  1863.     //    echo $verseStartIndex . ";;". $verseEndIndex;
  1864.             $sBookUrl $book->getUrl();
  1865.             if($bChapterLevel)
  1866.             {
  1867.                 $sSliderUrl $this->get('router')->generate('bible_slider_chapter', array(
  1868.                     'translationUrl' => $sTranslationUrl,
  1869.                     'bookUrl' => $sBookUrl,
  1870.                     'chapterIndex' => $chapterStartIndex
  1871.                 ));    
  1872.             }
  1873.             elseif($bVerseLevel)
  1874.             {
  1875.                 $sSliderUrl $this->get('router')->generate('bible_slider_verse', array(
  1876.                     'translationUrl' => $sTranslationUrl,
  1877.                     'bookUrl' => $sBookUrl,
  1878.                     'chapterIndex' => $chapterStartIndex,
  1879.                     'verseStartIndex' => $verseStartIndex
  1880.                 ));
  1881.             }
  1882.             else if($chapterEndIndex != null && $verseStartIndex != null)
  1883.             {
  1884.                 $sSliderUrl $this->get('router')->generate('bible_slider_chapter_range', array(
  1885.                     'translationUrl' => $sTranslationUrl,
  1886.                     'bookUrl' => $sBookUrl,
  1887.                     'chapterStartIndex' => $chapterStartIndex,
  1888.                     'chapterEndIndex' => $chapterEndIndex
  1889.                 ));
  1890.             }
  1891.             else if($chapterEndIndex != null && $verseStartIndex == null)
  1892.             {
  1893.                 $sSliderUrl $this->get('router')->generate('bible_slider_chapter_verse_range', array(
  1894.                     'translationUrl' => $sTranslationUrl,
  1895.                     'bookUrl' => $sBookUrl,
  1896.                     'chapterStartIndex' => $chapterStartIndex,
  1897.                     'chapterEndIndex' => $chapterEndIndex,
  1898.                     'verseStartIndex' => $verseStartIndex,
  1899.                     'verseEndIndex' => $verseEndIndex
  1900.                 ));
  1901.             }
  1902.             else
  1903.             {
  1904.                 $sSliderUrl $this->get('router')->generate('bible_slider_verserange', array(
  1905.                     'translationUrl' => $sTranslationUrl,
  1906.                     'bookUrl' => $sBookUrl,
  1907.                     'chapterIndex' => $chapterStartIndex,
  1908.                     'verseStartIndex' => $verseStartIndex,
  1909.                     'verseEndIndex' => $verseEndIndex
  1910.                 ));
  1911.             }
  1912.         }
  1913.                       
  1914.         $aOTLE $this->getOTLERefForBible($aVerseInfo, array(), true);                     
  1915.    //     $otle_ref = $aOTLE['otle_nonmusic']; 
  1916.         $otle_ref_music $aOTLE['otle_music'];
  1917.         
  1918.     //    $book_list = array();
  1919.         if(empty($translation) && !empty($allVerses))                    
  1920.              $translation $this->getBibleTranslationByChapter($nChapterIdfalse);
  1921.         
  1922.         if (empty($translation)) {
  1923.             $right_to_left False;    
  1924.         } else {
  1925.             $right_to_left $translation['righttoleft'];    
  1926.     //        $book_list = $this->getBibleBookListForMultiColumn($translation['id']);
  1927.         }
  1928.                 
  1929.         if($book !== null && $firstChapter !== null && $verses !== null)
  1930.             $qbible_link $this->getQBibleUrl($book$firstChapter$verses$isCanonical);
  1931.         
  1932.         if($book !== null && $firstChapter !== null)    
  1933.             $commentary_with_doc $this->getCommentaryWithDocForBible($book$firstChapter->getOrdering(), $isCanonical);    
  1934.         
  1935.         //$verseExplanations = DataAssembly::filterExplainedVerses($verses, $this->getManager());
  1936.         $verseExplanations $this->getFirstExplainedVerse($aVerseInfo$request);
  1937.         
  1938.         $sTranslatPattern1 $domainIndicator '_';
  1939.         $sTranslatPattern2 '';
  1940.         if($bStoryText
  1941.         {
  1942.             $sTranslatPattern1 .= $sStoryUrl '_';
  1943.         }
  1944.         else
  1945.         {
  1946.             $sTranslatPattern2 '_' $nChapterNum;
  1947.             if($bVerseLevel)
  1948.                 $sTranslatPattern2 .= '_' $sVerseIndex;
  1949.         }    
  1950.         
  1951.         $bible_column_spec '';
  1952.         if($bChapterLevel || $bVerseLevel)
  1953.              $bible_column_spec $columnDetails;
  1954.          else
  1955.          {
  1956.              $bible_column_spec $this->getBibleMultiColumnSpec($sTranslationUrl$book->getUrl(), $chapterStartIndex$verseStartIndex$verseEndIndex);
  1957.          }
  1958.     
  1959.         $rval = array(
  1960.             'column_type' => 'bible',
  1961.             'content_category' => $contentCategory,
  1962.             'canonically_numbered' => $isCanonical,
  1963.             'book' => $book,
  1964.             'curr_book' => $curr_book,
  1965.             'translation' => $translation,
  1966.             'contents' => $verses,
  1967.             'content_start_bound' => $rangeStart,
  1968.             'content_end_bound' => $rangeEnd,
  1969.             'translate_pattern1' => $sTranslatPattern1,
  1970.             'translate_pattern2' => $sTranslatPattern2,
  1971.             'has_slider_item' => $bHasSliderItem,
  1972.             'slider_url' => $sSliderUrl,
  1973.    /*         'referring_passages' => $referringPassages,
  1974.             'core_passages' => $corePassages,     */  
  1975.             'verses_concept' => $this->getVerseContentWithConceptLinks($request$allVerses$bible_column_spec$column_number),
  1976.             'right_to_left' => $right_to_left,    
  1977.             'prev_chapter' => $prevChapter,
  1978.             'next_chapter' => $nextChapter,   
  1979.             'prev_verse' => $prevVerse,
  1980.             'next_verse' => $nextVerse,
  1981.             'chapter_explanation' => $chapterExplanation,
  1982.             'explained_verse' => $verseExplanations,
  1983.             'qbible_link' => $qbible_link,
  1984.             'commentary_with_doc' => $commentary_with_doc
  1985.         //    'book_list' => $book_list,
  1986.             'story_translation_url' => $sStoryTranslationUrl,
  1987.             'chapter_id' => $nChapterId,
  1988.             'verse_id' => $nVerseId,            
  1989.             'otle_ref_music' => $otle_ref_music
  1990.         );
  1991.         
  1992.         if(!empty($chapterExplanation))
  1993.           {
  1994.               $nTransID current($chapterExplanation)['translation_id'];
  1995.               $explanation_translation $this->expositionData('Translation')->findOneById($nTransID);
  1996.               
  1997.               if($explanation_translation != null)
  1998.               {
  1999.                   $passage $explanation_translation->getWork()->findFirstNonEmptyPassage($explanation_translation);
  2000.                   if($passage != null)
  2001.                   {    
  2002.                       $rval['explanation_text_style_override'] = $this->getTextStyleOverride($nTransID);
  2003.                       $rval['explanation_translation'] = $explanation_translation;
  2004.                       $rval['explanation_passage'] = $passage;
  2005.                       $rval['explanation_authors'] = $this->getAuthorInfo($request$nTransID);
  2006.                       $rval['explanation_text_to_speech'] = $this->getTextToSpeech($explanation_translation->getLanguage()->getId());
  2007.                       $chapterData['passage_ref'] = $this->getWorkPassageRefs($passage->getId(),$nTransID$request);
  2008.                       $rval['passage_multilink'] = $this->getWorkPassageMultiLink($passage->getId(),$nTransID$request);
  2009.                       $rval['explanation_col1_ref'] = $columnDetails;
  2010.                       $rval['explanation_col2_ref'] = $this->MULTI_URL_INDICATOR_EXPLANATION "_" $explanation_translation->getUrl();
  2011.                       
  2012.                       $nExplainChapterID $this->getExplainChapterID($nTransID$this->getCurrUserID($request));        
  2013.                       if(!empty($nExplainChapterID))
  2014.                       {
  2015.                           $rval['explanation_cchapter_id'] = $nExplainChapterID;  
  2016.                           $rval['explanation_translation_id'] = $nTransID;                                  
  2017.                       }                      
  2018.                   }
  2019.               }    
  2020.           }
  2021.                   
  2022.         if($book != null)
  2023.         {
  2024.             $nBookID null;
  2025.             if($isCanonical)
  2026.                 $nBookID $book->getId();
  2027.             else
  2028.                 $nBookID $book->getCanonicalization()->getId();    
  2029.          
  2030.             $rval['translations_by_language'] = $this->getBibleTranslationsByLanguageForVerses($curr_book->getCanonicalization()->getId(), current($allVerses)->getChapter()->getOrdering(), current($allVerses)->getIndexDisplay(), end($allVerses)->getChapter()->getOrdering(), end($allVerses)->getIndexDisplay()); 
  2031.             
  2032.             $rval['cbook_id'] = $curr_book->getCanonicalization()->getId();
  2033.             $rval['verse_start_index'] = current($allVerses)->getIndexDisplay();
  2034.             $rval['chapter_end_order'] = end($allVerses)->getChapter()->getOrdering();
  2035.             $rval['verse_end_index'] = end($allVerses)->getIndexDisplay();
  2036.    
  2037.         }
  2038.         if($contentCategory === 'st') {
  2039.             $rval['story'] = $story;    
  2040.             $rval['multi_story_column'] = '1';          
  2041.         } else {            
  2042.            // $rval['verse_story'] = $this->getStoriesForVerses($aVerseInfo, $request);
  2043.         }
  2044.   /*      if(count($verses) === 0) {
  2045.             $rval['errors'][] = array('code' => 404, 'message' => 'translationmismatch.bible');
  2046.         } */
  2047.         
  2048.         if($translation != null)
  2049.         {
  2050.             $msgData $this->checkBibleTranslationMsg($translation['url']); 
  2051.           if(!empty($msgData))
  2052.           {              
  2053.               $rval['contents'] = null;
  2054.               $rval['no_content_msg'] = $msgData['no_content_msg'];
  2055.           }
  2056.           
  2057.           $rval['text_style_override'] = $this->getTextStyleOverride($translation['language_id']);
  2058.           $rval['text_to_speech'] = $this->getTextToSpeech($translation['language_id']);
  2059.           $rval['bible_credit'] = $this->getBibleTranslationCredit($translation['url']);
  2060.           $rval['translation_url'] = $translation['url'];
  2061.           $rval['book_url'] = $book->getUrl();
  2062.           $rval['chapter_order'] = $chapterStartIndex;
  2063.           $rval['chapter_index'] = $chapterStartIndex;
  2064.           $rval['hide_highlights'] = !$this->showBibleHighlights($translation['language_id']);
  2065.           $rval['translation_name'] = $translation['name'];
  2066.          } 
  2067.          
  2068.          if($bVerseLevel)
  2069.          {
  2070.              // get meta description
  2071.              $nTextLength 140;
  2072.              $sVerseContent current($allVerses)->getContent(); 
  2073.               $sMetaDesc $this->fixVerseText($sVerseContent);   
  2074.               $sMetaDesc $this->getTextWithinLength($sMetaDesc$nTextLength"...");          
  2075.               $rval['verse_meta_desc'] = $sMetaDesc;
  2076.           }
  2077.                   
  2078.         return $rval;
  2079.     }
  2080.     protected function expositionColumnDataNew($columnDetails$column_number$request$targetColumnNum null$renderingData null)
  2081.     {
  2082.         // Old Possible formats:
  2083.         // e_### (passage by id)
  2084.         // e_###_### (first number is passage id, second number is translation id)
  2085.         // e_w_### (first passage of work with given id)
  2086.         // e_t_### (first passage of translation with given id)
  2087.         // e_w_###_### (first number is id of a swedenborg work, second is section number -- use this to allow client-side generation of URLs for arbitrary Swedenborg sections)
  2088.         // e_t_###_### (as above, but first number is id of a specific translation)
  2089.         // e_xb_# (show explanation, if any, of the Bible story/verse/chapter in the specified column, e.g. e_ex_1 to show explanation)
  2090.         // e_xb_#_### (as above, but if that column doesn't show explained Bible content, then use the ExpositionTranslation whose ID is the second number)
  2091.         
  2092.         // new link e.g. swedenborg_divine-love-and-wisdom-dole_10
  2093.         // explanation_angels
  2094.         
  2095.         $bOnMobile $this->isOnMobile();
  2096.         $locale $request->getLocale();
  2097.         $dataElementDetails explode('_'strtolower($columnDetails));
  2098.         $domainIndicator array_shift($dataElementDetails);
  2099.         $columnSpec $dataElementDetails;
  2100.         $rval = array('column_type' => 'exposition');
  2101.         
  2102.         $nSpecCount count($columnSpec); 
  2103.         $bSwedenborgWork = ($domainIndicator === $this->MULTI_URL_INDICATOR_SWEDENBORG_WORK);
  2104.         $sTranslationUrl array_shift($columnSpec);
  2105.   
  2106.         $work null;
  2107.                         
  2108.         // Find specified work or translation            
  2109.         $rval['lock_translation'] = true;        
  2110.         $rval['translation'] = $this->expositionData('Translation')->findOneBy(array('url' => $sTranslationUrl'isPublic' => true'type_id' => $this->TRANSLATION_TYPE_ID_TEXT));    
  2111.         if($rval['translation'] != null) {       
  2112.             $work $rval['translation']->getWork();
  2113.         } 
  2114.         else
  2115.             return array();     
  2116.             
  2117.         $rval['is_swedenborg'] = $bSwedenborgWork;          
  2118.       
  2119.         if(empty($columnSpec) || !$bSwedenborgWork) {
  2120.             // No section number specified; use first passage
  2121.             $rval['passage'] = $work->findFirstNonEmptyPassage($rval['translation']);           
  2122.         } else {
  2123.         
  2124.             if($bSwedenborgWork)
  2125.             {
  2126.                 // Swedenborg section number specified
  2127.                 if($work == null || $work->getSwedenborgType() === null) {
  2128.                     $rval['errors'][] = array('code' => 404'message' => 'notswedenborg');
  2129.                     return $rval;
  2130.                 }
  2131.                 $sectionNum array_shift($columnSpec);            
  2132.                 $rval['passage'] = $this->expositionData('Passage')->findSwedenborgSection($work$sectionNum);
  2133.                 if($rval['passage'] === null) {
  2134.                     $rval['passage'] = (intval($sectionNum) <= 1) ? $work->findFirstNonEmptyPassage($rval['translation']) : $work->findLastPassage();
  2135.                 }
  2136.             }            
  2137.         }
  2138.         
  2139.          if($rval['passage'] == null) {  
  2140.             return array(); 
  2141.          }    
  2142.                  
  2143.          if(!$bSwedenborgWork)
  2144.             $rval['authors'] = $this->getAuthorInfo($request$rval['translation']->getId());
  2145.          else
  2146.             $rval['IsSwedenborgWork'] = 1;    
  2147.        
  2148.                                 
  2149.         $bCheckTrans = ($this->language1 == null);
  2150.         if($bCheckTrans)
  2151.         {
  2152.             $this->language1 $rval['translation']->getLanguage();
  2153.             $this->work1 $work;
  2154.         }
  2155.                
  2156.         if($work !== null && !$bSwedenborgWork) {
  2157.             // get concept illustrations
  2158.             $sConceptUrl $this->getConceptUrl($work->getId());            
  2159.             if($sConceptUrl != '')
  2160.             {
  2161.                 $concept $this->getRepository('Concepts\Concept')->findOneByUrl($sConceptUrl);
  2162.                 if($concept !== null) {
  2163.                     $illustrations $concept->getIllustrations();    
  2164.                     $rval['image'] = ($illustrations->isEmpty()) ? null $illustrations[0]->getImage();
  2165.                     $rval['concept_prev_next'] = $this->getNextPrevConceptUrl($rval['translation']->getId(), $rval['translation']->getLanguage()->getId(), $locale);
  2166.                 }
  2167.             }
  2168.             
  2169.             $bConsider false;
  2170.             $bBibleStudy false;            
  2171.             foreach($work->getCategories() as $category) {
  2172.                 if($category->getId() == 13) {
  2173.                     $bConsider true;
  2174.                 }
  2175.                 
  2176.                 if($category->getId() == 14) {
  2177.                     $bBibleStudy true;
  2178.                 }
  2179.             }           
  2180.             
  2181.             if($bConsider)
  2182.             {
  2183.                 $rval['consider_data'] = $this->getConsiderList($locale);
  2184.             }
  2185.             
  2186.             if($bBibleStudy)
  2187.             {
  2188.                 $rval['biblestudy_data'] = $this->getBibleStudyList($locale);
  2189.             }
  2190.         }
  2191.         
  2192.         if($rval['translation'] != null)
  2193.         {
  2194.             $nLanguageID $rval['translation']->getLanguage()->getId();
  2195.             $rval['text_style_override'] = $this->getTextStyleOverride($nLanguageID);            
  2196.             $rval['ref_column_spec'] = $columnDetails;
  2197.             $rval['text_to_speech'] = $this->getTextToSpeech($nLanguageID);     
  2198.             
  2199.             if($bSwedenborgWork)        
  2200.                 $rval['biblio_info'] = $this->getBiblioForTranslation($rval['translation']->getId()); 
  2201.             else
  2202.             {
  2203.                 $nExplainChapterID $this->getExplainChapterID($rval['translation']->getId(), $this->getCurrUserID($request));        
  2204.                   if(!empty($nExplainChapterID))
  2205.                   {                  
  2206.                       if($request->getSession()->get('has_explanation_cchapter_id_temp_trans') == '1')
  2207.                     {
  2208.                         // For multi-column views, explain chapter icon is not shown 
  2209.                         // if there are more than 1 chapter column
  2210.                         $request->getSession()->set('current_explanation_cchapter_id_temp_trans''');
  2211.                         $request->getSession()->set('current_explanation_translation_id_temp_trans''');                    
  2212.                     }
  2213.                     else
  2214.                     {
  2215.                         $request->getSession()->set('has_explanation_cchapter_id_temp_trans''1'); 
  2216.                         $request->getSession()->set('current_explanation_cchapter_id_temp_trans'$nExplainChapterID); 
  2217.                           $request->getSession()->set('current_explanation_translation_id_temp_trans'$rval['translation']->getId());  
  2218.                     }       
  2219.                   } 
  2220.             }          
  2221.         }
  2222.       
  2223.         if($rval['translation'] != null && $rval['passage'] != null)
  2224.         {
  2225.             $nPassageID $rval['passage']->getId();
  2226.             $nTransID $rval['translation']->getId();
  2227.             $nLanguageID $rval['translation']->getLanguage()->getId();
  2228.             $rval['previous_passage'] = $this->getPreviousPassageWithContent($rval['passage'], $rval['translation']);            
  2229.             $rval['next_passage'] = $this->getNextPassageWithContent($rval['passage'], $rval['translation']);
  2230.             
  2231.             $rval['translation_shortname'] = $this->getWorkTranslationShortName($nTransID);
  2232.                             
  2233.             if($bSwedenborgWork)    
  2234.                 $rval['related_bible_ref'] = $this->getRelatedBibleRefForWork($nPassageID,$nTransID$request);
  2235.             else
  2236.             {
  2237.                 if(!$bOnMobile)
  2238.                     $rval['passage_ref'] = $this->getWorkPassageRefs($nPassageID,$nTransID$request);        
  2239.             }    
  2240.                     
  2241.             $rval['passage_footnote'] = $this->getPassageFootnotes($nPassageID,$nTransID);
  2242.             $rval['passage_multilink'] = $this->getWorkPassageMultiLink($nPassageID,$nTransID$request);
  2243.             
  2244.             if($nLanguageID == $this->LANGUAGE_ID_LATIN)
  2245.             {                
  2246.                 $rval['passage_scanimage'] = $this->getWorkPassageScanImageFileName($nPassageID);
  2247.                 $rval['define_latin_icon'] = 1;
  2248.             }
  2249.             
  2250.             if($bSwedenborgWork)
  2251.               {
  2252.                   $bHasSliderItem $this->hasSliderItemForWork($nPassageID$nTransID$request$nLanguageID);
  2253.                   $rval['has_slider_item_for_work'] = $bHasSliderItem;
  2254.                 if($bHasSliderItem)
  2255.                 {
  2256.                     $rval['slider_url'] = $this->get('router')->generate('exposition_slider', array(
  2257.                         'translationId' => $nTransID,
  2258.                         'passageId' => $nPassageID
  2259.                     ));
  2260.                 }
  2261.                 
  2262.                 if($rval['passage']->emptyInTranslation($rval['translation']))
  2263.                 {    
  2264.                     $rval['last_passage_num'] = $this->getLastAvailablePassageNum($nTransID);
  2265.                 } 
  2266.             }
  2267.             $rval['translation_url'] = $rval['translation']->getUrl();
  2268.             
  2269.             if(!$bSwedenborgWork)
  2270.               {
  2271.                   if ($this->canEditExplanation($request))                  
  2272.                       $rval['explanation_translation_id_to_edit'] = $nTransID;
  2273.               }    
  2274.               else if ($this->canEditWork($request))
  2275.               {
  2276.                   $rval['work_translation_id_to_edit'] = $nTransID;
  2277.                   $rval['work_passage_num_to_edit'] = $rval['passage']->getSwedenborgSection();        
  2278.               }
  2279.               
  2280.               // check table of contents
  2281.               $aTOC $this->getWorkTranslationTOC($nTransIDtrue); 
  2282.               if(!empty($aTOC))
  2283.               {                  
  2284.                   $rval['has_work_toc'] = true;
  2285.               }
  2286.         } 
  2287.         
  2288.         return $rval;
  2289.     }
  2290. }