src/Ox/HoardBundle/Controller/SearchController.php line 296

Open in your IDE?
  1. <?php
  2. namespace App\Ox\HoardBundle\Controller;
  3. use Symfony\Component\HttpFoundation\Request;
  4. use Symfony\Component\HttpFoundation\Response;
  5. use Symfony\Component\HttpFoundation\JsonResponse;
  6. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  7. use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
  8. use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
  9. use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
  10. use Symfony\Component\Security\Core\Exception\AccessDeniedException;
  11. use Symfony\Component\Security\Core\Security;
  12. use Doctrine\ORM\Query\Expr\Select;
  13. use Doctrine\ORM\Query\Expr\From;
  14. use Symfony\Component\Form\Extension\Core\Type\SubmitType;
  15. use Symfony\Component\Form\Extension\Core\Type\ButtonType;
  16. use Symfony\Component\Form\Extension\Core\Type\HiddenType;
  17. use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
  18. use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
  19. use Knp\Component\Pager\PaginatorInterface;
  20. use App\Ox\HoardBundle\Entity\Hoard;
  21. use App\Ox\HoardBundle\Entity\HObject;
  22. use App\Ox\HoardBundle\Entity\Coin;
  23. use App\Ox\HoardBundle\Entity\Container;
  24. use App\Ox\HoardBundle\Entity\HoardCoinCount;
  25. use App\Ox\HoardBundle\Entity\HoardImage;
  26. use App\Ox\HoardBundle\Entity\OcreLookup;
  27. use App\Ox\HoardBundle\Form\HoardType;
  28. use App\Ox\HoardBundle\Form\HoardSearchType;
  29. use App\Ox\HoardBundle\Form\SummaryCoinType;
  30. use App\Ox\HoardBundle\Form\SearchType;
  31. /**
  32.  * Hoard controller.
  33.  *
  34.  * @Route("/search")
  35.  */
  36. class SearchController extends AbstractController
  37. {
  38.     private $security;
  39.     public function __construct(Security $security)
  40.     {
  41.         $this->security $security;
  42.     }
  43.     
  44.     /**
  45.      * Show an excel-like editing interface for a list of hoards
  46.      *
  47.      * @Route("/editmultiple", name="hoard_bulk_edit", methods={"GET"})
  48.      * @Template()
  49.      */
  50.     public function massEditAction(Request $request) {
  51.         
  52.         $em $this->getDoctrine()->getManager();
  53.         
  54.         //get all available options for the various dropdowns
  55.         $data = array();
  56.         $data['hoardTypes'] = $em->getRepository('OxHoardBundle:HoardType')->findAll();
  57.         $data['countries'] = $em->getRepository('OxHoardBundle:Country')->findAll();
  58.         $data['provinces'] = $em->getRepository('OxHoardBundle:Province')->findAll();
  59.         $data['findSpotLocationDetails'] = $em->getRepository('OxHoardBundle:FindSpotLocationDetail')->findAll();
  60.         $data['ancientPlaces'] = $em->getRepository('OxHoardBundle:AncientPlace')->findAll();
  61.         $data['reigns'] = $em->getRepository('OxHoardBundle:Reign')->findAll();
  62.         $data['discoveryMethods'] = $em->getRepository('OxHoardBundle:DiscoveryMethod')->findAll();
  63.         $data['discoveryLandUses'] = $em->getRepository('OxHoardBundle:DiscoveryLandUse')->findAll();
  64.         $data['archaeologyRecoveryMethods'] = $em->getRepository('OxHoardBundle:ArchaeologyRecoveryMethod')->findAll();
  65.         $data['archaeologySiteContexts'] = $em->getRepository('OxHoardBundle:ArchaeologySiteContext')->findAll();
  66.         $data['archaeologySiteContextDetails'] = $em->getRepository('OxHoardBundle:ArchaeologySiteContextDetail')->findAll();
  67.         $data['archaeologyPeriods'] = $em->getRepository('OxHoardBundle:ArchaeologyPeriod')->findAll();
  68.         $data['archaeologyContextNatures'] = $em->getRepository('OxHoardBundle:ArchaeologyContextNature')->findAll();
  69.         $data['coinLevelDatas'] = $em->getRepository('OxHoardBundle:CoinLevelData')->findAll();
  70.         $data['ratings'] = $em->getRepository('OxHoardBundle:Rating')->findAll();
  71.         $data['hideWhats'] = $em->getRepository('OxHoardBundle:HideWhat')->findAll();
  72.         $data['hideFroms'] = $em->getRepository('OxHoardBundle:HideFrom')->findAll();
  73.         return array(
  74.             'data' => $data
  75.         );
  76.     }
  77.     /**
  78.      * Lists all Hoard entities.
  79.      *
  80.      * @Route("/", name="hoard", methods={"GET", "POST"})
  81.      * @Template()
  82.      */
  83.     public function indexAction(Request $requestPaginatorInterface $paginator$isCoinsChart false) {
  84.         $activeTab 0;   // Default to Search tab
  85.         // var_dump($request);
  86.         // var_dump($request->query);
  87.         $search_type $request->query->get('search_type');
  88.         $format $request->query->get('format');
  89.         $initialSliderValues = array();
  90.         $initialSliderValues['hoardDiscoveryYearRangeStart'] = $this->getMinDiscoveryDate();
  91.         $initialSliderValues['hoardDiscoveryYearRangeEnd'] = $this->getMaxDiscoveryDate();
  92.         $initialSliderValues['hoardTerminalYearRangeStart'] = $this->getMinTerminalDate();
  93.         $initialSliderValues['hoardTerminalYearRangeEnd'] = $this->getMaxTerminalDate();
  94.         $initialSliderValues['hoardOpeningYearRangeStart'] = $this->getMinOpeningDate();
  95.         $initialSliderValues['hoardOpeningYearRangeEnd'] = $this->getMaxOpeningDate();
  96.         $initialSliderValues['hoardArchaeologyContextDateRangeStart'] = $this->getMinArchaeologyContextDate();
  97.         $initialSliderValues['hoardArchaeologyContextDateRangeEnd'] = $this->getMaxArchaeologyContextDate();
  98.         $coinminmax $this->getMinMaxCoinDate();
  99.         $initialSliderValues['coinYearRangeStart'] = $coinminmax['min1'];
  100.         $initialSliderValues['coinYearRangeEnd'] = $coinminmax['max1'];
  101.         $initialSliderValues['hoardCoinCountMin'] = 0;
  102.         $initialSliderValues['hoardCoinCountMax'] = 100000;
  103.         $isAdmin $this->userIsAdmin();
  104.         $isAuthenticated false;
  105.         if($this->getUser()) {
  106.             $isAuthenticated true;
  107.         }
  108.         
  109.         $searchHasCoinFields false;
  110.         
  111.         $limit 20;
  112.         $em $this->getDoctrine()->getManager();
  113.         $em->getFilters()->enable('softdeleteable');
  114.         if(isset($request->query->get('ox_hs')['rules']) && strlen($request->query->get('ox_hs')['rules'])) {
  115.           // this is an advanced search
  116.           
  117.           // check if coin fields are included in the search set $searchHasCoinFields
  118.           $rulesStr $request->query->get('ox_hs')['rules'];
  119.           if ( strpos($rulesStr'"field":"coin') || strpos($rulesStr'"field":"c.') ) {
  120.             $searchHasCoinFields true;
  121.           }
  122.           
  123.           $rules json_decode($rulesStrtrue);
  124.           $doctrineQueryBuilder $this->buildQuery($rules$search_type$format);
  125.           $activeTab 3;   // Set tab to Results tab
  126.         
  127.         else {
  128.             // this is a simple search
  129.             if ($request->query->get('ox_hs')) {
  130.                 foreach ($request->query->get('ox_hs') as $key => $value) {
  131.                     // check if coin fields are included in the search set $searchHasCoinFields
  132.                     if (substr$key0) === "coinYear") {
  133.                         if ($value != $initialSliderValues[$key]) {
  134.                             $searchHasCoinFields true;
  135.                         }
  136.                     } 
  137.                     elseif (substr$key0) === "coin") {
  138.                         if ($value && $value != "") {
  139.                             $searchHasCoinFields true;
  140.                         }
  141.                     }
  142.                 }
  143.             }
  144.           $doctrineQueryBuilder $em->createQueryBuilder()
  145.             ->andWhere('h IS NOT NULL'); // always exclude deleted hoards (this leftJoin('c.hoard', 'h') will include coins from deleted hoards)
  146.           $didJoinCoins false;
  147.           if ($format == 'csv-coins' || $format == 'csv') {
  148.             if ($format == 'csv-coins') {
  149.                 $doctrineQueryBuilder->select('h, c')->from('OxHoardBundle:Hoard''h')->leftJoin('h.coins''c');
  150.                 $didJoinCoins true;
  151.             } elseif ($format == 'csv') {
  152.                 if ($search_type == 'search-coins' ) {
  153.                     $doctrineQueryBuilder->select('h')->from('OxHoardBundle:Hoard''h')->leftJoin('h.coins''c');
  154.                     $didJoinCoins true;
  155.             } else {
  156.                     $doctrineQueryBuilder->select('h')->from('OxHoardBundle:Hoard''h');
  157.                 }
  158.             }
  159.           } else {
  160.               if ($search_type == 'search-coins' ) {
  161.                 $doctrineQueryBuilder->select('c, h')->from('OxHoardBundle:Coin''c')->leftJoin('c.hoard''h');
  162.                 $didJoinCoins true;
  163.             } else {
  164.                 $doctrineQueryBuilder->select('h')->from('OxHoardBundle:Hoard''h');
  165.               }
  166.           }
  167.           if (($search_type == 'search-coins' && $format != 'csv') ||
  168.             $format == 'csv-coins') {
  169.              $doctrineQueryBuilder
  170.                  ->addSelect('hcountriessort'// countries are going to be used for the results order
  171.                  ->leftJoin('h.countries''hcountriessort');
  172.           }
  173.           $coinValues  = array();
  174.           // find coin-related query params to join Coins if needed
  175.           if (!empty($request->query->get('ox_hs'))) {
  176.             foreach ($request->query->get('ox_hs') as $key => $value) {
  177.                 if (is_array($value) or strlen($value)) {
  178.                     if (strpos($key'coin') === 0) {
  179.                         $coinValues[$key] = $value;
  180.                     }
  181.                 }
  182.             }
  183.           }
  184.           //ignore coin year range if set to initial values
  185.           if(isset($coinValues['coinYearRangeStart']) && $coinValues['coinYearRangeStart'] == $initialSliderValues['coinYearRangeStart']) {
  186.             unset($coinValues['coinYearRangeStart']);
  187.           }
  188.           if(isset($coinValues['coinYearRangeEnd']) && $coinValues['coinYearRangeEnd'] == $initialSliderValues['coinYearRangeEnd']) {
  189.             unset($coinValues['coinYearRangeEnd']);
  190.           }
  191.           // only join coins to hoards if coins fields were used
  192.           if (!$didJoinCoins && count($coinValues) > 0) {
  193.             $doctrineQueryBuilder->leftJoin('h.coins''c');
  194.           }
  195.           // If the request is a POST, read the POST parameters from the search form and construct a search query
  196.           $hoardValues = array();
  197.           $coinValues  = array();
  198.           $queryParameters = array();
  199.           if (!empty($request->query->get('ox_hs'))) {
  200.               $this->constructSearchQuery($request$doctrineQueryBuilder$activeTab,
  201.                                           $hoardValues$coinValues$queryParameters$initialSliderValues);
  202.           }
  203.           //apply the 'only mine'
  204.           if (isset($request->query->get('ox_hs')['showOnlyUsersHoards'])) {
  205.               $doctrineQueryBuilder->andWhere('(h.created = :queryUser) OR (h.modified = :queryUser)')
  206.               ->setParameter('queryUser'$this->getUser());
  207.           }
  208.           
  209.           foreach ($queryParameters as $key => $value) {
  210.               $doctrineQueryBuilder->setParameter($key$value);
  211.           }
  212.         }
  213.         // Add handling of boundaries set for maps.
  214.         $boundary = isset($request->query->get('ox_hs')["boundary"]) ?
  215.             $request->query->get('ox_hs')["boundary"] :
  216.             null;
  217.         if ($boundary) {
  218.             $doctrineQueryBuilder->andWhere('ST_Contains(ST_GEOMFROMTEXT(\'Polygon((' $boundary '))\'), Point(h.findSpotLatitude, h.findSpotLongitude)) = true');
  219.         }
  220.         if (!$isAuthenticated) {
  221.             // public can only see hoards which are validated by the user,
  222.             // and which are either not hidden, or don't have everything hidden
  223.             $doctrineQueryBuilder->andWhere('(h.validatedByUser = true) AND (h.hideFrom = 3 OR h.hideWhat < 3 OR h.hideWhat IS NULL)');
  224.             // if coin fields are included in the search
  225.             if ($searchHasCoinFields) {
  226.                 // public can only see hoards with coins which are validated by the user,
  227.                 // and which are either not hidden, or don't have anything hidden
  228.                 $doctrineQueryBuilder->andWhere('(h.coinDataValidatedByUser = true) AND (h.hideFrom = 3 OR h.hideWhat IS NULL)');
  229.             }
  230.         }
  231.         // decide the order of the items
  232.         if ($format == 'csv-coins') {
  233.             $doctrineQueryBuilder->orderBy('hcountriessort.country''ASC');
  234.             $doctrineQueryBuilder->orderBy('h.findSpotName''ASC');
  235.             $doctrineQueryBuilder->orderBy('h.id''DESC');
  236.         }
  237.         else if ($format == 'csv'|| $search_type != 'search-coins') {
  238.             $sort $request->query->get('sort');
  239.             if ($this->getUser() && !$sort) {
  240.                 $sort 'h.modifiedDate';
  241.             }
  242.             $sortDirection $request->query->get('direction');
  243.             
  244.             if (!$sortDirection){
  245.                 // default to ascending except for modified/creationDate
  246.                 if ($sort=='h.modifiedDate' || $sort=='h.creationDate') {
  247.                     $sortDirection "DESC";
  248.                 } 
  249.                 else {
  250.                     $sortDirection "ASC";
  251.                 }
  252.             }
  253.             
  254.             if ($sort) {
  255.                 $doctrineQueryBuilder->orderBy($sort$sortDirection);
  256.             }
  257.         } 
  258.         else {
  259.             $doctrineQueryBuilder->orderBy('hcountriessort.country''ASC');
  260.             $doctrineQueryBuilder->orderBy('h.findSpotName''ASC');
  261.             $doctrineQueryBuilder->orderBy('h.id''DESC');
  262.         }
  263.         // if the indexAcion was called to produce the coin entries for the charts
  264.         if ($isCoinsChart) {
  265.             $doctrineQuery $doctrineQueryBuilder->getQuery();
  266.             return $doctrineQuery->getResult();
  267.         }
  268.         $MAX_HOARDS_IN_CHART 5000;
  269.         $doctrineQueryBuilderAllRows = clone $doctrineQueryBuilder;
  270.         $doctrineQuery $doctrineQueryBuilder->getQuery();
  271.         
  272.         // we have to use paginator to find if results are more than 1001 bacause doctrine distinct doesn't work as expected:
  273.         // https://stackoverflow.com/questions/50199102/setmaxresults-does-not-works-fine-when-doctrine-query-has-join
  274.         $paginatorAllRows $paginator->paginate(
  275.             $doctrineQueryBuilderAllRows->getQuery(),
  276.             $request->query->getInt('page'1),
  277.             $MAX_HOARDS_IN_CHART+1
  278.         );
  279.         $c count($paginatorAllRows);
  280.         $allHoards = array();
  281.         $allHoardResults = array();
  282.         $hoardsOverEditLimit true;
  283.         $hoardsOverChartLimit true;
  284.         if ($c 1000) {
  285.             $hoardsOverEditLimit false;
  286.         }
  287.         if ($c <= $MAX_HOARDS_IN_CHART) {
  288.           $hoardsOverChartLimit false;
  289.           $doctrineQueryBuilderAllRows->distinct();
  290.           $doctrineQueryAllRows $doctrineQueryBuilderAllRows->getQuery();
  291.           $allHoardResults $doctrineQueryAllRows->getResult();
  292.           foreach (array_slice($allHoardResults01000) as $hoard) {
  293.             $h = array();
  294.             $h['id'] = $hoard->getId();
  295.             if ($this->checkAccess($hoard'edit'false)) {
  296.               $h['permission'] = true;
  297.             } else {
  298.               $h['permission'] = false;
  299.             }
  300.             array_push($allHoards$h);
  301.           }
  302.         }
  303.         if ($format == 'csv') {
  304.             //join up all of the relevant tables
  305.             $doctrineQueryBuilder ->addSelect(
  306.                             'partial type.{id, hoardType}',
  307.                             'coinCount',
  308.                             'partial countries.{id, country}',
  309.                             'partial province.{id, province}',
  310.                             'partial coinLevelData.{id, coinLevelData}',
  311.                             'partial ancientPlace.{id, ancientPlace}',
  312.                             'partial location_detail.{id, findSpotLocationDetail}',
  313.                             'partial reign1.{id, reign}',
  314.                             'partial reign2.{id, reign}',
  315.                             'partial disc_method.{id, discoveryMethod}',
  316.                             'partial disc_landuse.{id, discoveryLandUse}',
  317.                             'partial recovery_method.{id, archaeologyRecoveryMethod}',
  318.                             'partial site_context.{id, archaeologySiteContext}',
  319.                             'partial site_context_details.{id, archaeologySiteContextDetail}',
  320.                             'partial arch_period.{id, archaeologyPeriod}',
  321.                             'partial arch_end_period.{id, archaeologyPeriod}',
  322.                             'partial context_natures.{id, title}',
  323.                             'partial findspot_rating.{id, rating}',
  324.                             'partial contextual_rating.{id, rating}',
  325.                             'partial rating.{id, rating}',
  326.                             'partial containers.{id, container}',
  327.                             'partial objects.{id, object}',
  328.                             'partial hoardReferences.{id, reference_str}',
  329.                             'partial references.{id, abbreviation, authors, year, title}',
  330.                             'partial refType.{id}',
  331.                         )
  332.                     ->leftJoin('h.hoardType''type')
  333.                 ->leftJoin('h.coinCount''coinCount')
  334.                 ->leftJoin('h.countries''countries')
  335.                 ->leftJoin('h.province''province')
  336.                 ->leftJoin('h.coinLevelData''coinLevelData')
  337.                 ->leftJoin('h.ancientPlace''ancientPlace')
  338.                 ->leftJoin('h.findSpotLocationDetail''location_detail')
  339.                 ->leftJoin('h.closingReign1''reign1')
  340.                 ->leftJoin('h.closingReign2''reign2')
  341.                 ->leftJoin('h.discoveryMethod''disc_method')
  342.                 ->leftJoin('h.discoveryLandUse''disc_landuse')
  343.                 ->leftJoin('h.archaeologyRecoveryMethod''recovery_method')
  344.                 ->leftJoin('h.archaeologySiteContext''site_context')
  345.                 ->leftJoin('h.archaeologySiteContextDetails''site_context_details')
  346.                 ->leftJoin('h.archaeologyPeriod''arch_period')
  347.                 ->leftJoin('h.archaeologyContextNatures''context_natures')
  348.                 ->leftJoin('h.archaeologyEndPeriod''arch_end_period')
  349.                 ->leftJoin('h.findSpotRating''findspot_rating')
  350.                 ->leftJoin('h.contextualRating''contextual_rating')
  351.                 ->leftJoin('h.rating''rating')
  352.                 ->leftJoin('h.containers''containers')
  353.                 ->leftJoin('h.objects''objects')
  354.                 ->leftJoin('h.hoardReferences''hoardReferences')
  355.                 ->leftJoin('hoardReferences.reference''references')
  356.                 ->leftJoin('references.referenceType''refType')
  357.             ;
  358.             $data $doctrineQueryBuilder->getQuery()->getArrayResult();
  359.             //loop over hoards and flag if they should be hidden
  360.             foreach($data as &$hoard) {
  361.                 if($isAuthenticated) {
  362.                     $hoard['can_see_location'] = true;
  363.                 } else {
  364.                     $hoard['can_see_location'] = !$hoard['hideLocation'];
  365.                 }
  366.                 
  367.                 $hoardOnlineDatabases = array();
  368.                 $hoard['hoardReferences'] = array_filter($hoard['hoardReferences'], function($reference) use (&$hoardOnlineDatabases) {
  369.                     if ($reference && $reference['reference'] &&
  370.                         $reference['reference']['referenceType'] &&
  371.                         $reference['reference']['referenceType']['id'] &&
  372.                         $reference['reference']['referenceType']['id'] != '11') { // reference's type is a "Permalink in other online database"
  373.                             return true;
  374.                     } else {
  375.                         $hoardOnlineDatabases[] = $reference;
  376.                         return false;
  377.                     }
  378.                 });
  379.                 $hoard['hoardOnlineDatabases'] = $hoardOnlineDatabases;
  380.             }
  381.             return $this->outputCSV($data'hoard_export');
  382.         }
  383.         if ($format == 'csv-coins') {
  384.             $doctrineQueryBuilder ->addSelect('
  385.                 partial cp.{id, period}, 
  386.                 partial cd.{id, denomination}, 
  387.                 partial cmat.{id, material}, 
  388.                 partial cmint.{id, mint}, 
  389.                 partial cr.{id, reign}, 
  390.                 partial cpers.{id, person, title}, 
  391.                 partial ccond.{id, condition}, 
  392.                 partial ca.{id, aspect},
  393.                 partial container.{id, container},
  394.                 partial coinAdditionalFields.{id, comment},
  395.                 partial additionalFields.{id, additionalField, description},
  396.                 partial coinRefs.{id, reference_str, comment},
  397.                 partial refs.{id, abbreviation, authors, year, title, sortValue, hasOwnColumn}
  398.                 '
  399.             );
  400.             
  401.             $doctrineQueryBuilder
  402.                 ->leftJoin('c.period''cp')
  403.                 ->leftJoin('c.denominations''cd')
  404.                 ->leftJoin('cd.material''cmat')
  405.                 ->leftJoin('c.mints''cmint')
  406.                 ->leftJoin('c.reigns''cr')
  407.                 ->leftJoin('c.persons''cpers')
  408.                 ->leftJoin('c.condition''ccond')
  409.                 ->leftJoin('c.aspects''ca')
  410.                 ->leftJoin('c.container''container')
  411.                 ->leftJoin('c.coinAdditionalFields''coinAdditionalFields')
  412.                 ->leftJoin('coinAdditionalFields.additionalField''additionalFields')
  413.                 ->leftJoin('c.coinReferences''coinRefs')
  414.                 ->leftJoin('coinRefs.reference''refs')
  415.             ;
  416.             $data $doctrineQueryBuilder->getQuery()->getArrayResult();
  417.             
  418.             $refData $this->processHoardDataForCSV($data);
  419.             return $this->outputCSV($data'coins_export'true$refData);
  420.         }
  421.         $coinTotalQuantity null;
  422.         if ($search_type == 'search-coins') {
  423.             $doctrineQueryBuilderCoinQuantity = clone $doctrineQueryBuilder;
  424.             $coinTotalQuantityQuery $doctrineQueryBuilderCoinQuantity
  425.                 ->select("c.id, c.quantity as q")
  426.                 ->getQuery()
  427.                 ->getArrayResult();
  428.             $uniqQuantities array_unique($coinTotalQuantityQuerySORT_REGULAR);
  429.             $coinTotalQuantity array_sum(array_column($uniqQuantities'q'));
  430.         }
  431.         $pagination $paginator->paginate(
  432.             $doctrineQuery,
  433.             $request->query->getInt('page'1)/*page number*/,
  434.             $limit/*limit per page*/
  435.         );
  436.         $sortFields = array(
  437.             array('label' => 'Hoard number''key' => 'h.id'),
  438.             array('label' => 'Find Spot Name''key' => 'h.findSpotName'),
  439.             array('label' => 'Discovery Year''key' => 'h.discoveryYear1'),
  440.             array('label' => 'Terminal Year''key' => 'h.terminalYear1'),
  441.             array('label' => 'Opening Year''key' => 'h.openingYear1'),
  442.             array('label' => 'Date of Context''key' => 'h.archaeologyContextDate1'),
  443.             array('label' => 'Date Added''key' => 'h.creationDate'),
  444.             array('label' => 'Date Modified''key' => 'h.modifiedDate')
  445.         );
  446.         $searchForm $this->createSearchForm();
  447.         $searchForm->handleRequest($request);
  448.         $hoardDiscoveryYearRangeStart $initialSliderValues['hoardDiscoveryYearRangeStart'];
  449.         if (isset($hoardValues['hoardDiscoveryYearRangeStart'])) {
  450.             $hoardDiscoveryYearRangeStart $hoardValues['hoardDiscoveryYearRangeStart'];
  451.         }
  452.         $hoardDiscoveryYearRangeEnd $initialSliderValues['hoardDiscoveryYearRangeEnd'];
  453.         if (isset($hoardValues['hoardDiscoveryYearRangeEnd'])) {
  454.             $hoardDiscoveryYearRangeEnd $hoardValues['hoardDiscoveryYearRangeEnd'] ;
  455.         }
  456.         $hoardTerminalYearRangeStart $initialSliderValues['hoardTerminalYearRangeStart'];
  457.         if (isset($hoardValues['hoardTerminalYearRangeStart'])) {
  458.             $hoardTerminalYearRangeStart $hoardValues['hoardTerminalYearRangeStart'] ;
  459.         }
  460.         $hoardTerminalYearRangeEnd $initialSliderValues['hoardTerminalYearRangeEnd'];
  461.         if (isset($hoardValues['hoardTerminalYearRangeEnd'])) {
  462.             $hoardTerminalYearRangeEnd $hoardValues['hoardTerminalYearRangeEnd'] ;
  463.         }
  464.         $hoardOpeningYearRangeStart $initialSliderValues['hoardOpeningYearRangeStart'];
  465.         if (isset($hoardValues['hoardOpeningYearRangeStart'])) {
  466.             $hoardOpeningYearRangeStart $hoardValues['hoardOpeningYearRangeStart'] ;
  467.         }
  468.         $hoardOpeningYearRangeEnd $initialSliderValues['hoardOpeningYearRangeEnd'];
  469.         if (isset($hoardValues['hoardOpeningYearRangeEnd'])) {
  470.             $hoardOpeningYearRangeEnd $hoardValues['hoardOpeningYearRangeEnd'] ;
  471.         }
  472.         $hoardArchaeologyContextDateRangeStart $initialSliderValues['hoardArchaeologyContextDateRangeStart'];
  473.         if (isset($hoardValues['hoardArchaeologyContextDateRangeStart'])) {
  474.             $hoardArchaeologyContextDateRangeStart $hoardValues['hoardArchaeologyContextDateRangeStart'];
  475.         }
  476.         $hoardArchaeologyContextDateRangeEnd $initialSliderValues['hoardArchaeologyContextDateRangeEnd'];
  477.         if (isset($hoardValues['hoardArchaeologyContextDateRangeEnd'])) {
  478.             $hoardArchaeologyContextDateRangeEnd $hoardValues['hoardArchaeologyContextDateRangeEnd'] ;
  479.         }
  480.         $coinYearRangeStart $initialSliderValues['coinYearRangeStart'];
  481.         if (isset($coinValues['coinYearRangeStart'])) {
  482.             $coinYearRangeStart $coinValues['coinYearRangeStart'];
  483.         }
  484.         $coinYearRangeEnd $initialSliderValues['coinYearRangeEnd'];
  485.         if (isset($coinValues['coinYearRangeEnd'])) {
  486.             $coinYearRangeEnd $coinValues['coinYearRangeEnd'];
  487.         }
  488.         $hoardCoinCountMin $initialSliderValues['hoardCoinCountMin'];
  489.         if (isset($hoardValues['hoardCoinCountMin'])) {
  490.             $hoardCoinCountMin $hoardValues['hoardCoinCountMin'] ;
  491.         }
  492.         $hoardCoinCountMax $initialSliderValues['hoardCoinCountMax'];
  493.         if (isset($hoardValues['hoardCoinCountMax'])) {
  494.             $hoardCoinCountMax $hoardValues['hoardCoinCountMax'] ;
  495.         }
  496.         foreach ($pagination as $hoard) {
  497.             if ($this->checkAccess($hoard'edit'false)) {
  498.                 $hoard->isEditableByUser true;
  499.             }
  500.             else {
  501.                 $hoard->isEditableByUser false;
  502.             }
  503.         }
  504.         $queryOptions $this->queryOptions();
  505.         
  506.         // use the coins or hoards template depending on the search type
  507.         if ($search_type == 'search-coins') {
  508.             $search_template '@OxHoardBundle/search/coinslist.html.twig';
  509.         } 
  510.         else {
  511.             $search_template '@OxHoardBundle/search/list.html.twig';
  512.         }
  513.         // parameters to template
  514.         return $this->render($search_template,
  515.             array(
  516.                 'pagination' => $pagination,
  517.                 'is_authenticated' => $isAuthenticated,
  518.                 'is_authorised_to_create' => $this->userIsAuthorisedToCreate(),
  519.                 'is_authorised_to_import' => $this->userIsImporter(),
  520.                 'is_admin'  => $isAdmin,
  521.                 'sort_fields' => $sortFields,
  522.                 'current_sort' => $sort ?? NULL,
  523.                 'current_sort_direction' => $sortDirection ?? NULL,
  524.                 'search_form'   => $searchForm->createView(),
  525.                 'active_tab' => $activeTab,
  526.                 'hoardDiscoveryYearRangeStart' => $hoardDiscoveryYearRangeStart,
  527.                 'hoardDiscoveryYearRangeEnd' => $hoardDiscoveryYearRangeEnd,
  528.                 'hoardTerminalYearRangeStart' => $hoardTerminalYearRangeStart,
  529.                 'hoardTerminalYearRangeEnd' => $hoardTerminalYearRangeEnd,
  530.                 'hoardOpeningYearRangeStart' => $hoardOpeningYearRangeStart,
  531.                 'hoardOpeningYearRangeEnd' => $hoardOpeningYearRangeEnd,
  532.                 'coinYearRangeStart' => $coinYearRangeStart,
  533.                 'coinYearRangeEnd' => $coinYearRangeEnd,
  534.                 'hoardArchaeologyContextDateRangeStart' => $hoardArchaeologyContextDateRangeStart,
  535.                 'hoardArchaeologyContextDateRangeEnd' => $hoardArchaeologyContextDateRangeEnd,
  536.                 'hoardCoinCountMin' => $hoardCoinCountMin,
  537.                 'hoardCoinCountMax' => $hoardCoinCountMax,
  538.                 'initialHoardDiscoveryYearRangeStart' => $initialSliderValues['hoardDiscoveryYearRangeStart'],
  539.                 'initialHoardDiscoveryYearRangeEnd' => $initialSliderValues['hoardDiscoveryYearRangeEnd'],
  540.                 'initialHoardTerminalYearRangeStart' => $initialSliderValues['hoardTerminalYearRangeStart'],
  541.                 'initialHoardTerminalYearRangeEnd' => $initialSliderValues['hoardTerminalYearRangeEnd'],
  542.                 'initialHoardOpeningYearRangeStart' => $initialSliderValues['hoardOpeningYearRangeStart'],
  543.                 'initialHoardOpeningYearRangeEnd' => $initialSliderValues['hoardOpeningYearRangeEnd'],
  544.                 'initialHoardArchaeologyContextDateRangeStart' => $initialSliderValues['hoardArchaeologyContextDateRangeStart'],
  545.                 'initialHoardArchaeologyContextDateRangeEnd' => $initialSliderValues['hoardArchaeologyContextDateRangeEnd'],
  546.                 'initialHoardCoinCountMin' => $initialSliderValues['hoardCoinCountMin'],
  547.                 'initialHoardCoinCountMax' => $initialSliderValues['hoardCoinCountMax'],
  548.                 'initialCoinYearRangeStart' => $initialSliderValues['coinYearRangeStart'],
  549.                 'initialCoinYearRangeEnd' => $initialSliderValues['coinYearRangeEnd'],
  550.                 'initialCoinYearRangeStart' => $initialSliderValues['coinYearRangeStart'],
  551.                 'initialCoinYearRangeEnd' => $initialSliderValues['coinYearRangeEnd'],
  552.                 'queryOptions' => $queryOptions,
  553.                 'allHoardResults' => $allHoards,
  554.                 'hoardsOverEditLimit' => $hoardsOverEditLimit,
  555.                 'hoardsOverChartLimit' => $hoardsOverChartLimit,
  556.                 // 'allHoardsChart' => $allHoardChartResults,
  557.                 'allHoardsChart' => $allHoardResults,
  558.                 'coinTotalQuantity' => $coinTotalQuantity,
  559.                 'queryString' => $request->getQueryString(),
  560.                 'search_type' => $search_type
  561.             ));
  562.     }
  563.     /**
  564.      * creates csv and appropriate page response for csv of supplied query
  565.      *
  566.      */
  567.     private function outputCSV(Array $data$prefix=null$exportCoins=false$refData=null) {
  568.         
  569.         if($prefix == null) {
  570.             $prefix "export";
  571.         }
  572.         $filename $prefix."_".date("Y_m_d_His").".csv";
  573.         if($exportCoins) {
  574.             //build an array of column headings for the reference columns
  575.             if($refData) {
  576.                 $refHeadings = [];
  577.                 foreach($refData['own_column_references'] as $o_c_ref) {
  578.                     if(isset($o_c_ref['abbreviation'])) {
  579.                         $refHeadings[] = $o_c_ref['abbreviation'] . ' Reference';
  580.                     } else {
  581.                         $refHeadings[] = $o_c_ref['title'] . ' Reference';
  582.                     }
  583.                 }
  584.                 for($i=1$i <= $refData['num_other_references']; $i++) {
  585.                     $refHeadings[] = 'Other Reference '.$i;
  586.                 }
  587.             }
  588.             $response $this->render('@OxHoardBundle/coin/csvExport.html.twig', array(
  589.                                             'data' => $data,
  590.                                             // 'numRefs' => 10,
  591.                                             'ref_headings' => $refHeadings,
  592.                                             'num_ref_columns' => count($refHeadings)
  593.                                         ));
  594.         } else {
  595.             $response $this->render('@OxHoardBundle/hoard/csvExport.html.twig', array(
  596.                 'is_authenticated' => !!$this->getUser(),
  597.                 'data' => $data
  598.             ));
  599.         }
  600.         
  601.         $response->headers->set('Content-Type''text/csv');
  602.         $response->setStatusCode(200);
  603.         $response->setCharset('UTF-8');
  604.         $response->headers->set('Content-Type''text/csv');
  605.         $response->headers->set('Content-Description''Hoards Export');
  606.         $response->headers->set('Content-Disposition''attachment; filename='.$filename);
  607.         $response->headers->set('Content-Transfer-Encoding''binary');
  608.         $response->headers->set('Pragma''no-cache');
  609.         $response->headers->set('Expires''0');
  610.         return $response;
  611.      }
  612.     /**
  613.     * Creates a form to search Hoard entities.
  614.     *
  615.     * @return \Symfony\Component\Form\Form The form
  616.     */
  617.     private function createSearchForm()
  618.     {
  619.         $form $this->createForm(SearchType::class, null, array(
  620.             'action' => $this->generateUrl('hoard'),
  621.             'method' => 'GET',
  622.         ));
  623.         if($this->getUser()) {
  624.             // $form->add('hoardHideLocation', ChoiceType::class, array(
  625.             //     'choices' => array('Yes' => true, 'No' => false),
  626.             //     'required' => false,
  627.             // ));
  628.             //add the validated by user option
  629.             $form->add('hoardValidatedByUser'ChoiceType::class, array(
  630.                 'choices' => array('Yes' => true'No' => false),
  631.                 'required' => false,
  632.             ));
  633.             $form->add('hoardCoinDataValidatedByUser'ChoiceType::class, array(
  634.                 'choices' => array('Yes' => true'No' => false),
  635.                 'required' => false,
  636.             ));
  637.             $form->add('showOnlyUsersHoards'CheckboxType::class, array(
  638.                 'required' => false
  639.             ));
  640.         }
  641.         if($this->userIsAdmin()) {
  642.             //add the validated by user option
  643.             $form->add('hoardValidatedByAdmin'ChoiceType::class, array(
  644.                 'choices' => array('Yes' => true'No' => false),
  645.                 'required' => false,
  646.             ));
  647.             $form->add('hoardCoinDataValidatedByAdmin'ChoiceType::class, array(
  648.                 'choices' => array('Yes' => true'No' => false),
  649.                 'required' => false,
  650.             ));
  651.         }
  652.         $form->add('rules'HiddenType::class, array());
  653.         $form->add('boundary'HiddenType::class, array());
  654.         
  655.         // these fields have to be added to the for to make this message dissapear:
  656.         // "This form should not contain extra fields.""
  657.         // $form->add('hoardDiscoveryYearRangeStart', 'text', array('label' => '', 'required' => false))
  658.         //     ->add('hoardDiscoveryYearRangeEnd', 'text')
  659.         //     ->add('hoardTerminalYearRangeStart', 'text')
  660.         //     ->add('hoardTerminalYearRangeEnd', 'text')
  661.         //     ->add('coinYearRangeStart', 'text')
  662.         //     ->add('coinYearRangeEnd', 'text')
  663.         //     ->add('hoardCoinCountMin', 'text')
  664.         //     ->add('hoardCoinCountMax', 'text');
  665.         $form->add('submit'SubmitType::class, array('label' => 'Search hoards'));
  666.         $form->add('coin_submit'SubmitType::class, array('label' => 'Search coins'));
  667.         return $form;
  668.     }
  669.     
  670.     //process the hoard data
  671.     // This sorts the coins and normalises the references to consistent columns 
  672.     private function processHoardDataForCSV(&$data) {
  673.         $seenOwnColumnReferences = [];
  674.         $seenOtherReferences = [];
  675.     
  676.         //sort the references by sort value
  677.         foreach($data as &$hoard) {
  678.             foreach($hoard['coins'] as &$coin) {
  679.                 //get the sort value
  680.                 $reigns $coin['reigns'];
  681.                 if ($reigns && count($reigns)) {
  682.                     // just look at first reign
  683.                     $reign $reigns[0];
  684.                     $lookups = isset($reign['ocreLookups']) ?
  685.                         $reign['ocreLookups'] :
  686.                         [];
  687.                     foreach($lookups as $lookup) {
  688.                         $coinPersons = [];
  689.                         foreach($coin['persons'] as $person) {
  690.                             $coinPersons[] = $person['id'];
  691.                         }
  692.                         if (in_array($lookup['person']['id'], $coinPersons)) {
  693.                             // check mint if necessary
  694.                             if (isset($lookup['mint'])) {
  695.                                 // see if it matches
  696.                                 $coinMints = [];
  697.                                 foreach ($coin['mints'] as $mint) {
  698.                                     $coinMints[] = $mint['id'];
  699.                                 }
  700.                                 if (in_array($lookup['mint']['id'], $coinMints)) {
  701.                                     // this is a match
  702.                                     $coin['sortValue'] = $lookup['sortValue'];
  703.                                 }
  704.                             } 
  705.                             else {
  706.                                 // this is a match
  707.                                 $coin['sortValue'] = $lookup['sortValue'];
  708.                             }
  709.                         }
  710.                     }
  711.                 }
  712.                 // echo '<pre>'; print_r($coin); echo '</pre>';
  713.                 
  714.                 //note which references are seen
  715.                 // keep separate arrays of references which should have their own column
  716.                 foreach($coin['coinReferences'] as $coinRef) {
  717.                     $ref $coinRef['reference'];
  718.                     if($ref) {
  719.                         if($coinRef['reference']['hasOwnColumn']) {
  720.                             if(!in_array($ref$seenOwnColumnReferences)) {
  721.                                 $seenOwnColumnReferences[] = $ref;
  722.                             }
  723.                         } else {
  724.                             if(!in_array($ref$seenOtherReferences)) {
  725.                                 $seenOtherReferences[] = $ref;
  726.                             }
  727.                         }
  728.                     }
  729.                 }
  730.                 
  731.                 usort($coin['coinReferences'], array($this,"compareRefs"));
  732.             }
  733.             
  734.             
  735.             //now sort coins by their sort value
  736.             usort($seenOwnColumnReferences, array($this,"compareSeenRefs"));
  737.             usort($hoard['coins'], array($this,"compareCoins"));
  738.             
  739.             // var_dump($hoard);
  740.         }
  741.         //at this point we have a list of coin references seen in this dataset, and the coin references are sorted
  742.         
  743.         //rewrite the coin references with the references in the relevant columns
  744.         $maxOtherReferences 0;
  745.         foreach($data as &$hoard) {
  746.             foreach($hoard['coins'] as &$coin) {
  747.                 //keyed array of those references which should have their own column
  748.                 $newOwnColumnCoinReferences = [];
  749.                 
  750.                 //plain array of all other references
  751.                 $newOtherCoinReferences = [];
  752.                 
  753.                 $coinReferences $coin['coinReferences'];
  754.                 foreach($coinReferences as $coinRef) {
  755.                     if(isset($coinRef['reference']) && $coinRef['reference']['hasOwnColumn']) {
  756.                         $key $coinRef['reference']['id'];
  757.                         $newOwnColumnCoinReferences[$key] = $coinRef;
  758.                     } else {
  759.                         $newOtherCoinReferences[] = $coinRef;
  760.                     }
  761.                 }
  762.                 
  763.                 
  764.                 
  765.                 //now build the full array of references
  766.                 $newCoinReferences = [];
  767.                 
  768.                 // var_dump($seenOwnColumnReferences);
  769.                 foreach($seenOwnColumnReferences as $ownColumnRef) {
  770.                     $val '';
  771.                     // var_dump($seenOwnColumnReferences);
  772.                     if(isset($newOwnColumnCoinReferences[$ownColumnRef['id']])) {
  773.                         
  774.                         $val $newOwnColumnCoinReferences[$ownColumnRef['id']];
  775.                     } else {
  776.                         $val = array();
  777.                     }
  778.                     $newCoinReferences[] = $val;
  779.                 }
  780.                 
  781.                 //keep track of how many columns we need
  782.                 if(count($newOtherCoinReferences) > $maxOtherReferences) {
  783.                     $maxOtherReferences count($newOtherCoinReferences);
  784.                 }
  785.                 
  786.                 
  787.                 //add the non-own-column references
  788.                 $newCoinReferences array_merge($newCoinReferences$newOtherCoinReferences);
  789.                 $coin['coinReferences'] = $newCoinReferences;
  790.             }
  791.         }
  792.         
  793.         //return some data about the references seen
  794.         return array(
  795.             'own_column_references' => $seenOwnColumnReferences,
  796.             'num_other_references' => $maxOtherReferences
  797.         );
  798.     }
  799.     function compareCoins($a$b) {
  800.         //compare period
  801.         if (isset($a['period'])) { $periodA $a['period']['id']; } else { $periodA 0; }
  802.         if (isset($b['period'])) { $periodB $b['period']['id']; } else { $periodB 0; }
  803.         if($periodA $periodB) { return -1; }
  804.         else if($periodB $periodA ) { return 1; }
  805.         else {
  806.             if(isset($a['sortValue'])) { $sortA $a['sortValue']; } else { $sortA 0; }
  807.             if(isset($b['sortValue'])) { $sortB $b['sortValue']; } else { $sortB 0; }
  808.             //periods are equal, compare by ocre table
  809.             if($sortA $sortB) { return 1; }
  810.             else if($sortB $sortA) { return -1; }
  811.             else {
  812.                 //same ocre prefix
  813.                 //todo compare ric reference value
  814.                 $refValueA $this->getSortableRef($a);
  815.                 if($refValueA) {
  816.                     $refValueB $this->getSortableRef($b);
  817.                     if($refValueB) {
  818.                         //compare numerical part
  819.                         $numA intval($refValueA['num']);
  820.                         $numB intval($refValueB['num']);
  821.                         if($numA $numB) { return 1; }
  822.                         else if($numB $numA) {return -1; }
  823.                         else {
  824.                             //compare alphabetic part
  825.                             $lowerA strtolower($refValueA['char']);
  826.                             $lowerB strtolower($refValueB['char']);
  827.                             if($lowerA $lowerB) { return -1; }
  828.                             else if($lowerB $lowerA) { return 1; }
  829.                             else return 0;
  830.                         }
  831.                     }
  832.                 }
  833.                 
  834.                 return 0;
  835.             }
  836.         }
  837.     }
  838.     
  839.     //given an array of coinData, get the most relevant reference as an array of numerical part and alphabetic part
  840.     function getSortableRef($coinArray) {
  841.         // var_dump($coinArray);
  842.         foreach($coinArray['coinReferences'] as $coinRef) {
  843.             if(isset($coinRef['reference'])) {
  844.                 $refs = ['RIC''RIC (2nd ed.)''RRC''RPC'];
  845.                 if(in_array($coinRef['reference']['abbreviation'], $refs)) {
  846.                     //this is a reference we care about sorting on
  847.                     //extract the numerical and alphabetic components
  848.                     $matches null;
  849.                     if (preg_match('/(\d+)\/(\d+)(\w*)/'$coinRef['reference_str'], $matches)) {
  850.                         //RRC reference format e.g. 123/1b
  851.                         //derive a number that can be used to compare
  852.                         $num $matches[1] * 1000 $matches[2];
  853.                         $refData = array(
  854.                             'num' => $num,
  855.                             'char' => $matches[3]
  856.                         );
  857.                         return $refData;
  858.                     } else if (preg_match('/(\d+)(\w*)/'$coinRef['reference_str'], $matches)) {
  859.                         //RIC reference format e.g. 123a (or somethings 123a/b or )
  860.                         $refData = array(
  861.                             'num' => $matches[1],
  862.                             'char' => $matches[2]
  863.                         );
  864.                         return $refData;
  865.                     }
  866.                 }
  867.             }
  868.         }
  869.         return null;
  870.     }
  871.     //order coinreference array data by sortvalue of the reference (decreasing)
  872.     function compareSeenRefs($a$b) {
  873.         if($a['sortValue'] > $b['sortValue']) {
  874.             return -1;
  875.         } else if ($a['sortValue'] == $b['sortValue']) {
  876.             return 0;
  877.         } else {
  878.             return 1;
  879.         }
  880.     }
  881.     //order coinreference array data by sortvalue of the reference (decreasing)
  882.     function compareRefs($a$b) {
  883.         if($a['reference']['sortValue'] > $b['reference']['sortValue']) {
  884.             return -1;
  885.         } else if ($a['reference']['sortValue'] == $b['reference']['sortValue']) {
  886.             return 0;
  887.         } else {
  888.             return 1;
  889.         }
  890.     }
  891.     private function getMinDiscoveryDate() {
  892.         return 900;
  893.         // $em = $this->getDoctrine()->getManager();
  894.         // 
  895.         // // Generate the coin summaries
  896.         // $queryBuilder = $em->createQueryBuilder();
  897.         // $queryBuilder->select('MIN(h.discoveryYear1) as min1, MIN(h.discoveryYear2) as min2')
  898.         //     ->from('OxHoardBundle:Hoard', 'h');
  899.         // 
  900.         // $query = $queryBuilder->getQuery();
  901.         // 
  902.         // $queryResult = $query->getArrayResult();
  903.         // 
  904.         // if(count($queryResult)) {
  905.         //     return min($queryResult[0]);
  906.         // }
  907.         // else {
  908.         //     return 1750;
  909.         // }
  910.     }
  911.     private function getMaxDiscoveryDate() {
  912.         return date("Y");
  913.         // $em = $this->getDoctrine()->getManager();
  914.         // 
  915.         // // Generate the coin summaries
  916.         // $queryBuilder = $em->createQueryBuilder();
  917.         // $queryBuilder->select('MAX(h.discoveryYear1) as max1, MAX(h.discoveryYear2) as max2')
  918.         //     ->from('OxHoardBundle:Hoard', 'h');
  919.         // 
  920.         // $query = $queryBuilder->getQuery();
  921.         // 
  922.         // $queryResult = $query->getArrayResult();
  923.         // 
  924.         // if(count($queryResult)) {
  925.         //     return max($queryResult[0]);
  926.         // }
  927.         // else {
  928.         //     return date("Y");
  929.         // }
  930.     }
  931.     private function getMinTerminalDate() {
  932.         //checking every hoard v slow
  933.         return -500;
  934.         
  935.         // $em = $this->getDoctrine()->getManager();
  936.         // 
  937.         // // Generate the coin summaries
  938.         // $queryBuilder = $em->createQueryBuilder();
  939.         // $queryBuilder->select('MIN(h.terminalYear1) as min1, MIN(h.terminalYear2) as min2')
  940.         //     ->from('OxHoardBundle:Hoard', 'h');
  941.         // 
  942.         // $query = $queryBuilder->getQuery();
  943.         // 
  944.         // $queryResult = $query->getArrayResult();
  945.         // 
  946.         // if(count($queryResult)) {
  947.         //     return min($queryResult[0]);
  948.         // }
  949.         // else {
  950.         //     return -100;
  951.         // }
  952.     }
  953.     private function getMaxTerminalDate() {
  954.         //checking every hoard is rather slow.
  955.         return 1000;
  956.         
  957.         // $em = $this->getDoctrine()->getManager();
  958.         // 
  959.         // // Generate the coin summaries
  960.         // $queryBuilder = $em->createQueryBuilder();
  961.         // $queryBuilder->select('MAX(h.terminalYear1) as max1, MAX(h.terminalYear2) as max2')
  962.         //     ->from('OxHoardBundle:Hoard', 'h');
  963.         // 
  964.         // $query = $queryBuilder->getQuery();
  965.         // 
  966.         // $queryResult = $query->getArrayResult();
  967.         // 
  968.         // if(count($queryResult)) {
  969.         //     return max($queryResult[0]);
  970.         // }
  971.         // else {
  972.         //     return 550;
  973.         // }
  974.     }
  975.     
  976.     private function getMinOpeningDate() {
  977.         return -500;
  978.     
  979.     }
  980.     private function getMaxOpeningDate() {
  981.         return 1000;
  982.     }
  983.     private function getMinArchaeologyContextDate() {
  984.         return -500;
  985.     
  986.     }
  987.     private function getMaxArchaeologyContextDate() {
  988.         return 1000;
  989.     }
  990.     private function getMinMaxCoinDate() {
  991.         // $em = $this->getDoctrine()->getManager();
  992.         // $qb = $em->createQueryBuilder();
  993.         // $qb->select('MAX(c.endingDate) as max1, MIN(c.startingDate) as min1')
  994.         //     ->from('OxHoardBundle:Coin', 'c');
  995.         //     
  996.         // $query = $qb->getQuery();
  997.         // $result = $query->getArrayResult();
  998.         // return $result[0];
  999.         return array('min1'=>-500'max1'=>1000);
  1000.         
  1001.         
  1002.     }
  1003.     /**
  1004.      * checks permission of user's current request
  1005.      *
  1006.      * @param mixed $entity The entity being validated
  1007.      *
  1008.      * @param string $attribute - 'view' or 'edit' or 'delete'
  1009.      *
  1010.      * @param boolean $throwException - whether to throw an exception if false - defaults to true
  1011.      *
  1012.      * @return boolean
  1013.      *
  1014.      * @throws \Symfony\Component\Security\Core\Exception\AccessDeniedException
  1015.      */
  1016.     private function checkAccess($entity$attribute$throwException true) {
  1017.         // call security voter(s)
  1018.         if (false === $this->security->isGranted($attribute$entity)) {
  1019.             if ($throwException) {
  1020.                 throw new AccessDeniedException('Unauthorised access!');
  1021.             }
  1022.             return false;
  1023.         }
  1024.         return true;
  1025.     }
  1026.     private function userIsAdmin() {
  1027.         if($this->getUser() && ($this->getUser()->hasRole('ROLE_ADMIN') || $this->getUser()->hasRole('ROLE_SUPER_ADMIN')))
  1028.         {
  1029.             return true;
  1030.         }
  1031.         return false;
  1032.     }
  1033.     private function userIsImporter() {
  1034.         if($this->getUser() && ($this->getUser()->hasRole('ROLE_IMPORTER')))
  1035.         {
  1036.             return true;
  1037.         }
  1038.         return $this->userIsAdmin();
  1039.     }
  1040.     private function userIsAuthorisedToCreate() {
  1041.         // user must either be admin or be authorised to edit hoards for at least one country
  1042.         if($this->userIsAdmin() || ($this->getUser() && count($this->getUser()->getAccessibleCountries()) > 0)) {
  1043.             return true;
  1044.         }
  1045.         return false;
  1046.     }
  1047.       /**
  1048.        * Retrieves coordinates of all the hoards from database
  1049.        *
  1050.        * @Route("/ajax_all_hoard_locations", name="ajax_all_hoard_locations", methods={"GET"})
  1051.        */
  1052.       public function ajaxAllHoardLocations()
  1053.       {
  1054.             $em $this->getDoctrine()->getManager();
  1055.             $queryBuilder $em -> createQueryBuilder()
  1056.                                 ->select("h.id, h.findSpotLatitude, h.findSpotLongitude, h.terminalYear1, h.terminalYear2, h.findSpotName, h.validatedByUser")
  1057.                                 ->from("OxHoardBundle:Hoard""h")
  1058.                                 ->where('h.findSpotLatitude IS NOT NULL')
  1059.                                 ->andWhere('h.findSpotLongitude IS NOT NULL');
  1060.             //filter list for public to only those 'published' (validated by user)
  1061.             if(!$this->getUser())
  1062.             {
  1063.                   //public can see all hoards which are not hidden from the public, and which don't have location hidden
  1064.                   $queryBuilder->andWhere('(h.hideFrom = 3 OR h.hideWhat < 3  OR h.hideWhat IS NULL)')
  1065.                                 ->andWhere('(h.hideLocation IS NULL OR h.hideLocation != 1)')
  1066.                                 ;
  1067.             }
  1068.             $query $queryBuilder->getQuery();
  1069.             
  1070.             $allHoards $query -> getArrayResult();
  1071.             return new JsonResponse(
  1072.                   $allHoards
  1073.             );
  1074.       }
  1075.       /***
  1076.          * Given a rules array, biuld a doctrine query
  1077.          *
  1078.          */
  1079.         private function buildQuery($rules$search_type$format) {
  1080.             $em $this->getDoctrine()->getManager();
  1081.             $qb $em->createQueryBuilder();
  1082.             
  1083.             // if format=csv select hoards. coins are going to be listed with a hoard.coins loop in the twig template
  1084.             if ($format == 'csv-coins' || $format == 'csv') {
  1085.                 $qb->add('select', new Select(array('h''c')))
  1086.                     ->add('from', new From('OxHoardBundle:Hoard''h'))
  1087.                     ->leftJoin('h.coins''c');
  1088.             } else {
  1089.                 if ($search_type == 'search-coins') {
  1090.                     $qb->add('select', new Select(array('c''h')))
  1091.                         ->add('from', new From('OxHoardBundle:Coin''c'))
  1092.                         ->leftJoin('c.hoard''h');
  1093.                 } else {
  1094.                     $qb->add('select', new Select(array('h''c')))
  1095.                         ->add('from', new From('OxHoardBundle:Hoard''h'))
  1096.                         ->leftJoin('h.coins''c');
  1097.                 }
  1098.             }
  1099.             if (($search_type == 'search-coins' && $format != 'csv') || $format == 'csv-coins') {
  1100.                 $qb->addSelect('hcountriessort')
  1101.                     ->leftJoin('h.countries''hcountriessort');
  1102.             }
  1103.             
  1104.         //set join flags to false 
  1105.         $this->joinHoardImages $this->joinHoardCountries $this->joinHoardArchaeologySiteContextDetail $this->joinCoinImages $this->joinCoinPersons =
  1106.         $this->joinCoinDenominations $this->joinCoinMints $this->joinCoinAspects $this->joinCoinCoinReferences =
  1107.         $this->joinCoinReferences $this->joinCoinReigns $this->joinContainers $this->joinContainerImages =
  1108.         $this->joinContainerForms $this->joinObjects $this->joinObjectImages 
  1109.         $this->joinHoardAncientPlaces $this->joinFindSpotLocationDetails $this->joinHoardReferences =
  1110.         $this->joinDiscoveryMethods $this->joinDiscoveryLandUses $this->joinNameSimple $this->joinArchaeologyContextNatures false;
  1111.         
  1112.             //build expression recursively
  1113.             $expr1 $this->getExpressionForRule($qb$rules);
  1114.             $qb->add('where'$expr1);
  1115.         
  1116.         //join tables if necessary
  1117.         if ($this->joinHoardCountries$qb->leftJoin('h.countries''hoardCountries');
  1118.         if ($this->joinHoardArchaeologySiteContextDetail$qb->leftJoin('h.archaeologySiteContextDetails''hoardArchaeologySiteContextDetails');
  1119.         if ($this->joinHoardImages$qb->leftJoin('h.hoardImages''hoardImages');
  1120.         if ($this->joinCoinImages$qb->leftJoin('c.coinImages''coinImages');
  1121.         if ($this->joinCoinPersons$qb->leftJoin('c.persons''coinPersons');
  1122.         if ($this->joinCoinDenominations$qb->leftJoin('c.denominations''coinDenominations');
  1123.         if ($this->joinCoinMints$qb->leftJoin('c.mints''coinMints');
  1124.         if ($this->joinCoinAspects$qb->leftJoin('c.aspects''coinAspects');
  1125.         if ($this->joinCoinCoinReferences$qb->leftJoin('c.coinReferences''coinCoinReferences');
  1126.         if ($this->joinCoinReferences$qb->leftJoin('coinCoinReferences.reference''coinReferences');
  1127.         if ($this->joinCoinReigns$qb->leftJoin('c.reigns''coinReigns');
  1128.         if ($this->joinContainers$qb->leftJoin('h.containers''containers');
  1129.         if ($this->joinContainerImages$qb->leftJoin('containers.containerImages''containerImages');
  1130.         if ($this->joinContainerForms$qb->leftJoin('containers.containerForm''containerForms');
  1131.         if ($this->joinObjects$qb->leftJoin('h.objects''objects');
  1132.         if ($this->joinObjectImages$qb->leftJoin('objects.objectImages''objectImages');
  1133.         if ($this->joinHoardReferences$qb->leftJoin('h.hoardReferences''hoardReferences');
  1134.         if ($this->joinHoardAncientPlaces$qb->leftJoin('h.ancientPlace''hoardAncientPlaces');
  1135.         if ($this->joinArchaeologyContextNatures$qb->leftJoin('h.archaeologyContextNatures''hoardArchaeologyContextNatures');
  1136.         if ($this->joinFindSpotLocationDetails$qb->leftJoin('h.findSpotLocationDetail''hoardFindSpotLocationDetails');
  1137.         if ($this->joinDiscoveryMethods$qb->leftJoin('h.discoveryMethod''hoardDiscoveryMethods');
  1138.         if ($this->joinDiscoveryLandUses$qb->leftJoin('h.discoveryLandUse''hoardDiscoveryLandUses');
  1139.         if ($this->joinNameSimple$qb->leftJoin('h.nameSimple''nameSimple');
  1140.             return $qb;
  1141.         }
  1142.       private function getExpressionForRule($qb$rule) {
  1143.             // Recursive function to build up an expression for the rule
  1144.             //  if this is a compound rule, make a boolean expression out of the sub-expressions
  1145.             //  otherwise make an atomic (simple) expression
  1146.             if(isset($rule['condition'])) {
  1147.                 //compound rule
  1148.                 $rules $rule['rules'];
  1149.                 switch($rule['condition']) {
  1150.                     case 'AND':
  1151.                         $expr $qb->expr()->andX();
  1152.                         break;
  1153.                     case 'OR':
  1154.                         $expr $qb->expr()->orX();
  1155.                         break;
  1156.                 }
  1157.                 foreach($rules as $rule) {
  1158.                     $subexpr $this->getExpressionForRule($qb$rule);
  1159.                     $expr->add($subexpr);
  1160.                 }
  1161.             } else {
  1162.                 //atomic rule
  1163.                 $expr $this->getExpressionForAtomicRule($qb$rule);
  1164.             }
  1165.             return $expr;
  1166.         }
  1167.         
  1168.         private function getExpressionForAtomicRule($qb$rule) {
  1169.         
  1170.         // get field
  1171.             $field $rule['field'];
  1172.             // get value
  1173.             $value $rule['value'];
  1174.             // get type
  1175.             $type $rule['type'];
  1176.             $is_array = isset($rule['data']['isArray']) ?
  1177.                 $rule['data']['isArray'] === true :
  1178.                 false;
  1179.             // get range: if the field is a range (eg discoveryYear1-discoveryYear2)
  1180.             // then $range is true and $fiald is discoveryYear
  1181.             $range false;
  1182.             $checkCollection false;
  1183.         // set join flags to true if necessary
  1184.         if( $field == 'hoardCountries.id') {
  1185.           $this->joinHoardCountries true;
  1186.         }
  1187.         if( $field == 'hoardArchaeologySiteContextDetails.id') {
  1188.             $this->joinHoardArchaeologySiteContextDetail true;
  1189.         }
  1190.         if( $field == 'ancientPlace') {
  1191.           $this->joinAncientPlaces true;
  1192.         }
  1193.         if( $field == 'hoardArchaeologyContextNatures.id') {
  1194.             $this->joinArchaeologyContextNatures true;
  1195.         }
  1196.         if( $field == 'findSpotLocationDetail') {
  1197.             $this->joinFindSpotLocationDetails true;
  1198.         }
  1199.         if( $field == 'discoveryMethod') {
  1200.             $this->joinDiscoveryMethods true;
  1201.         }
  1202.         if( $field == 'discoveryLandUse') {
  1203.             $this->joinDiscoveryLandUses true;
  1204.         }
  1205.         if( $field == 'hoardReferences.reference') {
  1206.             $this->joinHoardReferences true;
  1207.         }
  1208.         if( $field == 'hoardImages') {
  1209.           $this->joinHoardImages true;
  1210.         }
  1211.         if( $field == 'c.period') {
  1212.         }
  1213.         if( $field == 'coinPersons.id') {
  1214.           $this->joinCoinPersons true;
  1215.         }
  1216.         if( $field == 'coinReigns.id') {
  1217.           $this->joinCoinReigns true;
  1218.         }
  1219.         if( $field == 'coinDenominations.id') {
  1220.           $this->joinCoinDenominations true;
  1221.         }
  1222.         if( $field == 'coinDenominations.material') {
  1223.           $this->joinCoinDenominations true;
  1224.           
  1225.         }
  1226.         if( $field == 'coinMints.id') {
  1227.           $this->joinCoinMints true;
  1228.         }
  1229.         if( $field == 'coinAspects.id') {
  1230.           $this->joinCoinAspects true;
  1231.         }
  1232.         if( $field == 'coinReferences.id') {
  1233.           $this->joinCoinCoinReferences true;
  1234.           $this->joinCoinReferences true;
  1235.         }
  1236.         if( $field == 'coinCoinReferences.reference_str') {
  1237.           $this->joinCoinCoinReferences true;
  1238.           $this->joinCoinReferences true;
  1239.           $this->joinCoinReferences true;
  1240.         }
  1241.         if( $field == 'coinImages') {
  1242.           $this->joinCoinImages true;
  1243.         }
  1244.         if( $field == 'containers' || $field == 'containers.container' || $field == 'containers.comment') {
  1245.           $this->joinContainers true;
  1246.         }
  1247.         if( $field == 'containerImages') {
  1248.           $this->joinContainers true;
  1249.           $this->joinContainerImages true;
  1250.         }
  1251.         if( $field == 'containers.material') {
  1252.           $this->joinContainers true;
  1253.         }
  1254.         if( $field == 'containers.containerForm') {
  1255.           $this->joinContainers true;
  1256.           $this->joinContainerForms true;
  1257.         }
  1258.         if( $field == 'objects' || $field == 'objects.comment') {
  1259.           $this->joinObjects true;
  1260.         }
  1261.         if( $field == 'objectImages') {
  1262.           $this->joinObjects true;
  1263.           $this->joinObjectImages true;
  1264.         }
  1265.         if( $field == 'objects.object') {
  1266.           $this->joinObjects true;
  1267.         }
  1268.         if( $field == 'objects.material') {
  1269.           $this->joinObjects true;
  1270.         }
  1271.         if( $field == 'h.findSpotName') {
  1272.           $this->joinNameSimple true;
  1273.         }
  1274.         
  1275.             if (isset($rule['data'])) {
  1276.                 if (isset($rule['data']['range'])) {
  1277.                     $range $rule['data']['range'];
  1278.                 }
  1279.                 if (isset($rule['data']['checkCollection'])) {
  1280.                     $checkCollection $rule['data']['checkCollection'];
  1281.                 }
  1282.             }
  1283.             if(isset($rule['operator'])) {
  1284.                 $expr NULL;
  1285.               if ($field == 'h.findSpotName' && (
  1286.                   $rule['operator'] == 'begins_with' || $rule['operator'] == 'ends_with' ||
  1287.                   $rule['operator'] == 'contains' || $rule['operator'] == 'equal' || 'not_equal'
  1288.               )) {
  1289.                   switch($rule['operator']) {
  1290.                       case 'contains':
  1291.                       $newValue '%'.$value.'%';
  1292.                       $expr "(h.findSpotName LIKE '".$newValue."' OR h.findSpotOtherNames LIKE '".$newValue."' OR nameSimple.name LIKE '".$newValue."')";
  1293.                       break;
  1294.                       case 'equal':
  1295.                       $newValue $value;
  1296.                       $expr "(h.findSpotName = '".$newValue."' OR h.findSpotOtherNames = '".$newValue."' OR nameSimple.name = '".$newValue."')";
  1297.                       break;
  1298.                       case 'not_equal':
  1299.                       $newValue $value;
  1300.                       $expr "(h.findSpotName <> '".$newValue."' OR h.findSpotOtherNames <> '".$newValue."' OR nameSimple.name <> '".$newValue."')";
  1301.                       break;
  1302.                   }
  1303.               } 
  1304.               else {
  1305.                 switch($rule['operator']) {
  1306.                     case 'begins_with':
  1307.                         $expr $qb->expr()->like($field$qb->expr()->literal($value.'%'));
  1308.                         break;
  1309.                     case 'ends_with':
  1310.                         $expr $qb->expr()->like($field$qb->expr()->literal('%'.$value));
  1311.                     case 'contains':
  1312.                         $expr $qb->expr()->like($field$qb->expr()->literal('%'.$value.'%'));
  1313.                         break;
  1314.                     case 'equal':
  1315.                         if ($range) {
  1316.                             if ($type == "integer") {
  1317.                                 $expr '(' .$field'1 <= ' .$value' AND ' .$field'2 >= ' .$value') OR ' .$field'1 = ' .$value .' OR ' .$field'2 = ' .$value;
  1318.                                 break;
  1319.                             }
  1320.                         } else {
  1321.                             if ($type == "string") {
  1322.                                 if ($is_array) {
  1323.                                     $expr $field' IN (' .$value')';
  1324.                                 } else {
  1325.                                     $expr $qb->expr()->eq($field$qb->expr()->literal($value));
  1326.                                 }
  1327.                                 break;
  1328.                             }
  1329.                             if ($type == "integer" || $type == "double") {
  1330.                                 if ($field=="c.period") {
  1331.                                     $expr $field' = ' .$value;
  1332.                                 } else {
  1333.                                     $expr $field' = ' .$value;
  1334.                                 }
  1335.                                 break;
  1336.                             }
  1337.                             if ($type == "boolean") {
  1338.                                 if ($checkCollection) {
  1339.                                     if ($value == "true") {
  1340.                                         $expr $field' IS NOT NULL';
  1341.                                         break;
  1342.                                     } else {
  1343.                                         $expr $field' IS NULL';
  1344.                                         break;
  1345.                                     }
  1346.                                 }
  1347.                                 if ($field == "h.modified") {
  1348.                                     $currentUser $this->getUser()->getId();
  1349.                                     $expr 'h.modified = ' .$currentUser' OR h.created = ' .$currentUser;
  1350.                                     break;
  1351.                                 } else {
  1352.                                     $bool_value $value == false '0' $value;
  1353.                                     $expr $field' = ' .$bool_value;
  1354.                                     break;
  1355.                                 }
  1356.                             }
  1357.                         }
  1358.                         case 'not_equal':
  1359.                             if ($range) {
  1360.                                 if ($type == "integer") {
  1361.                                     $expr $field'1>' .$value.' OR ' .$field'2<' .$value.' OR (' .$field'1!=' .$value'AND ' .$field'2 IS NULL) OR (' .$field'2!=' .$value' AND ' .$field'1 IS NULL)' ;
  1362.                                     break;
  1363.                                 }
  1364.                             } else {
  1365.                                 if ($type == "string") {
  1366.                                     $expr $qb->expr()->neq($field$qb->expr()->literal($value));
  1367.                                     break;
  1368.                                 }
  1369.                                 if ($type == "integer" || $type == "double") {
  1370.                                     $expr $field'!=' .$value;
  1371.                                     break;
  1372.                                 }
  1373.                             }
  1374.                     case 'greater':
  1375.                         if ($range) {
  1376.                             $expr $field'1>' .$value' OR ' .$field'2>' .$value ;
  1377.                             break;
  1378.                         } else {
  1379.                             $expr $field'>' .$value;
  1380.                             break;
  1381.                         }
  1382.                     case 'less':
  1383.                         if ($range) {
  1384.                             $expr $field'2<' .$value' OR ' .$field'1<' .$value ;
  1385.                             break;
  1386.                         } else {
  1387.                             $expr $field'<' .$value;
  1388.                             break;
  1389.                         }
  1390.                     case 'is_null':
  1391.                             if ($range) {
  1392.                                 if ($type == "integer") {
  1393.                                     $expr $field'1 IS NULL AND ' .$field'2 IS NULL' ;
  1394.                                     break;
  1395.                                 }
  1396.                             } else {
  1397.                                 $expr $field.' IS NULL';
  1398.                                 break;
  1399.                             }
  1400.                     case 'is_not_null':
  1401.                             if ($range) {
  1402.                                 if ($type == "integer") {
  1403.                                     $expr $field'1 IS NOT NULL OR ' .$field'2 IS NOT NULL' ;
  1404.                                     break;
  1405.                                 }
  1406.                             } else {
  1407.                                 $expr $field.' IS NOT NULL';
  1408.                                 break;
  1409.                             }
  1410.                     default:
  1411.                         //error
  1412.                 }
  1413.               }
  1414.               if (($field == "h.city" || $field == "h.address") && !$this->getUser()) {
  1415.                   $expr $expr ' AND h.hideCity = 0 OR h.hideCity IS NULL';
  1416.               }
  1417.               if ($field == "h.county" && !$this->getUser()) {
  1418.                   $expr $expr ' AND h.hideCounty = 0 OR h.hideCounty IS NULL';
  1419.               }
  1420.               return $expr;
  1421.             } 
  1422.             else {
  1423.                 // error
  1424.             }
  1425.         }
  1426.         
  1427.         private function queryOptions() {
  1428.                 $em $this->getDoctrine()->getManager();
  1429.                 
  1430.                 //get all available options for the various dropdowns
  1431.                 $data = array();
  1432.                 $data['hoardTypes'] = $em->getRepository('OxHoardBundle:HoardType')->findAll();
  1433.                 $data['countries'] = $em->getRepository('OxHoardBundle:Country')->findAll();
  1434.                 $data['provinces'] = $em->getRepository('OxHoardBundle:Province')->findAll();
  1435.                 $data['ancientPlaces'] = $em->getRepository('OxHoardBundle:AncientPlace')->findAll();
  1436.                 $data['findSpotLocationDetails'] = $em->getRepository('OxHoardBundle:FindSpotLocationDetail')->findAll();
  1437.                 $data['discoveryLandUses'] = $em->getRepository('OxHoardBundle:DiscoveryLandUse')->findAll();
  1438.                 $data['discoveryMethods'] = $em->getRepository('OxHoardBundle:DiscoveryMethod')->findAll();
  1439.                 $data['reigns'] = $em->getRepository('OxHoardBundle:Reign')->findAll();
  1440.                 $data['discoveryMethods'] = $em->getRepository('OxHoardBundle:DiscoveryMethod')->findAll();
  1441.                 $data['discoveryLandUses'] = $em->getRepository('OxHoardBundle:DiscoveryLandUse')->findAll();
  1442.                 $data['archaeologyRecoveryMethods'] = $em->getRepository('OxHoardBundle:ArchaeologyRecoveryMethod')->findAll();
  1443.                 $data['archaeologySiteContexts'] = $em->getRepository('OxHoardBundle:ArchaeologySiteContext')->findAll();
  1444.                 $data['archaeologyRecoveryMethods'] = $em->getRepository('OxHoardBundle:ArchaeologyRecoveryMethod')->findAll();
  1445.                 $data['archaeologySiteContextDetails'] = $em->getRepository('OxHoardBundle:ArchaeologySiteContextDetail')->findAll();
  1446.                 $data['archaeologyPeriods'] = $em->getRepository('OxHoardBundle:ArchaeologyPeriod')->findAll();
  1447.                 $data['archaeologyContextNatures'] = $em->getRepository('OxHoardBundle:ArchaeologyContextNature')->findAll();
  1448.                 $data['coinLevelDatas'] = $em->getRepository('OxHoardBundle:CoinLevelData')->findAll();
  1449.                 $data['ratings'] = $em->getRepository('OxHoardBundle:Rating')->findAll();
  1450.                 $data['hideWhats'] = $em->getRepository('OxHoardBundle:HideWhat')->findAll();
  1451.                 $data['hideFroms'] = $em->getRepository('OxHoardBundle:HideFrom')->findAll();
  1452.                 $data['persons'] = $em->getRepository('OxHoardBundle:Person')->findAll();
  1453.                 $data['period'] = $em->getRepository('OxHoardBundle:Period')->findAll();
  1454.                 $data['reigns'] = $em->getRepository('OxHoardBundle:Reign')->findAll();
  1455.                 $data['mints'] = $em->getRepository('OxHoardBundle:Mint')->findAll();
  1456.                 $data['denominations'] = $em->getRepository('OxHoardBundle:Denomination')->findAll();
  1457.                 $data['materials'] = array(
  1458.                     array("ids" => "23""name" => "Gold"),
  1459.                     array("ids" => "22,31""name" => "Silver"),
  1460.                     array("ids" => "7,49,53""name" => "Bronze"),
  1461.                 );
  1462.                 $data['condition'] = $em->getRepository('OxHoardBundle:Condition')->findAll();
  1463.                 $data['aspects'] = $em->getRepository('OxHoardBundle:Aspect')->findAll();
  1464.                 $data['references'] = $em->getRepository('OxHoardBundle:Reference')->findBy(array(), array('sortValue' => 'DESC''authors' => 'ASC''title' => 'ASC'));
  1465.                 // var_dump($data['references']);
  1466.                 $data['containerForms'] = $em->getRepository('OxHoardBundle:ContainerForm')->findAll();
  1467.                 return $data;
  1468.         }
  1469.     private function constructSearchQuery($request, &$doctrineQueryBuilder, &$activeTab, &$hoardValues, &$coinValues, &$queryParameters$initialSliderValues)
  1470.     {
  1471.         // Construct a query based on all the form values.
  1472.         // We'll add JOINs and WHERE clauses to the doctrineQueryBuilder object.
  1473.         // We'll add any parameter values to the queryParameters array, and after this function join them to the existing query (they seemed to get lost if I added them directly to the doctrineQueryBuilder)
  1474.         // The hardValues and coinValues arrays will contain parameters appropriate to those objects and be populated by this function
  1475.         if (!empty($request->query->get('ox_hs'))) {
  1476.             foreach ($request->query->get('ox_hs') as $key => $value) {
  1477.                 if (is_array($value) or strlen($value)) {
  1478.                     if (strpos($key'hoard') === 0) {
  1479.                         $hoardValues[$key] = $value;
  1480.                     }
  1481.                     else if (strpos($key'coin') === 0) {
  1482.                         $coinValues[$key] = $value;
  1483.                     }
  1484.                 }
  1485.             }
  1486.         }
  1487.         if($this->userIsAdmin()) {
  1488.             #echo "<pre>hoard params: " . print_r($hoardValues,1) . "</pre>";
  1489.             #echo "<pre>coin params: " . print_r($coinValues,1) . "</pre>";
  1490.         }
  1491.         if (!empty($hoardValues)) {
  1492.             $isHoardRefJoined false;
  1493.             foreach ($hoardValues as $key => $value) {
  1494.                 $field lcfirst(substr($keystrlen('hoard')));
  1495.                 if ($field == "findSpotName") {
  1496.                     //   Search in both findSpotName and findSpotOtherNames fields
  1497.                     $altField "findSpotOtherNames";
  1498.                     $doctrineQueryBuilder->join('h.nameSimple''nameSimple');
  1499.                     $doctrineQueryBuilder->andWhere('h.' .$field' LIKE :' .$key' OR ' 'h.' .$altField' LIKE :' .$key' OR ' 'nameSimple.name LIKE :' .$key);
  1500.                     $queryParameters[$key] = '%'.$value.'%';
  1501.                 } else if ($field == "type") {
  1502.                     //   Search in both findSpotName and findSpotOtherNames fields
  1503.                     $doctrineQueryBuilder->andWhere('h.' 'hoardType' ' = :' $key);
  1504.                     $queryParameters[$key] = $value;
  1505.                 } else if ($field == "countries") {
  1506.                     $doctrineQueryBuilder->join('h.' 'countries''country');
  1507.                     
  1508.                     $fieldQuery "( ";
  1509.                     foreach ($value as $index => $val) {
  1510.                         if ($index 0) {
  1511.                             $fieldQuery .= " OR ";
  1512.                         }
  1513.                         $fieldQuery .= 'country.id = :' $key "_" $index;
  1514.                         $queryParameters[$key "_" $index] = $val;
  1515.                     }
  1516.                     $fieldQuery .= " )";
  1517.                     $doctrineQueryBuilder->andWhere($fieldQuery);
  1518.                 } else if (
  1519.                     $field == "comment" || $field == "credit" || $field == "region" ||
  1520.                     $field == "city" || $field == "county" || $field == "address" ||
  1521.                     $field == "owner" || $field == "findSpotComment" || $field == "finder" ||
  1522.                     $field == "archaeologyNaturalFeatures" || $field == "archaeologyAssociatedFeatures" ||
  1523.                     $field == "archaeologySiteComment" || $field == "internalNote"
  1524.                 ) {
  1525.                     $doctrineQueryBuilder->andWhere('h.' $field ' LIKE :' $key);
  1526.                     if (($field == "city" || $field == "address") && !$this->getUser()) {
  1527.                         $doctrineQueryBuilder->andWhere('h.hideCity = 0 OR h.hideCity IS NULL');
  1528.                     }
  1529.                     if ($field == "county" && !$this->getUser()) {
  1530.                         $doctrineQueryBuilder->andWhere('h.hideCounty = 0 OR h.hideCounty IS NULL');
  1531.                     }
  1532.                     $queryParameters[$key] = '%'.$value.'%';
  1533.                 } else if ($field == "archaeologyContextNatures") {
  1534.                     $doctrineQueryBuilder->join('h.' 'archaeologyContextNatures''archaeologyContextNatures');
  1535.                     $fieldQuery "( ";
  1536.                     foreach ($value as $index => $val) {
  1537.                         if ($index 0) {
  1538.                             $fieldQuery .= " OR ";
  1539.                         }
  1540.                         $fieldQuery .= 'archaeologyContextNatures.id = :' $key "_" $index;
  1541.                         $queryParameters[$key "_" $index] = $val;
  1542.                     }
  1543.                     $fieldQuery .= " )";
  1544.                     $doctrineQueryBuilder->andWhere($fieldQuery);
  1545.                 } else if ($field == "archaeologySiteContextDetails") {
  1546.                     $doctrineQueryBuilder->join('h.' 'archaeologySiteContextDetails''archaeologySiteContextDetail');
  1547.                     
  1548.                     $fieldQuery "( ";
  1549.                     foreach ($value as $index => $val) {
  1550.                         if ($index 0) {
  1551.                             $fieldQuery .= " OR ";
  1552.                         }
  1553.                         $fieldQuery .= 'archaeologySiteContextDetail.id = :' $key "_" $index;
  1554.                         $queryParameters[$key "_" $index] = $val;
  1555.                     }
  1556.                     $fieldQuery .= " )";
  1557.                     $doctrineQueryBuilder->andWhere($fieldQuery);
  1558.                 } else if ($field == "discoveryYearRangeStart") {
  1559.                     if ($hoardValues['hoardDiscoveryYearRangeEnd']) {
  1560.                         if (($hoardValues['hoardDiscoveryYearRangeStart'] == $initialSliderValues['hoardDiscoveryYearRangeStart'])
  1561.                             and ($hoardValues['hoardDiscoveryYearRangeEnd'] == $initialSliderValues['hoardDiscoveryYearRangeEnd'])) {
  1562.                             # Do nothing
  1563.                         } else {
  1564.                             $endKey "hoardDiscoveryYearRangeEnd";
  1565.                             $endValue $hoardValues['hoardDiscoveryYearRangeEnd'];
  1566.                             if ($hoardValues['hoardDiscoveryYearRangeStart'] > $initialSliderValues['hoardDiscoveryYearRangeStart']) {
  1567.                                 $rangeCondition  ' (h.' 'discoveryYear1' ' >= :' $key;
  1568.                                 $rangeCondition .=   ' AND h.' 'discoveryYear1' ' <= :' $endKey;
  1569.                                 $rangeCondition .= ' )';
  1570.                                 $rangeCondition .= ' OR ';
  1571.                                 $rangeCondition .= ' (h.' 'discoveryYear2' ' >= :' $key;
  1572.                                 $rangeCondition .=   '  AND h.' 'discoveryYear2' ' <= :' $endKey;
  1573.                                 $rangeCondition .= ' )';
  1574.                                 $doctrineQueryBuilder->andWhere($rangeCondition);
  1575.                                 $queryParameters[$key] = $value;
  1576.                                 $queryParameters[$endKey] = $endValue;
  1577.                             } else {
  1578.                                 # just search on end date
  1579.                                 $rangeCondition  ' h.' 'discoveryYear1' ' <= :' $endKey;
  1580.                                 $rangeCondition .= ' OR ';
  1581.                                 $rangeCondition .= ' h.' 'discoveryYear2' ' <= :' $endKey;
  1582.                                 $doctrineQueryBuilder->andWhere($rangeCondition);
  1583.                                 $queryParameters[$endKey] = $endValue;
  1584.                             }
  1585.                         }
  1586.                     } else {
  1587.                         if ($hoardValues['hoardDiscoveryYearRangeStart'] == $initialSliderValues['hoardDiscoveryYearRangeStart']) {
  1588.                             # Do nothing
  1589.                         } else {
  1590.                             $doctrineQueryBuilder->andWhere('h.' 'discoveryYear1' ' = :' $key);
  1591.                             $queryParameters[$key] = $value;
  1592.                         }
  1593.                     }
  1594.                 } else if ($field == "terminalYearRangeStart") {
  1595.                     if (isset($hoardValues['hoardTerminalYearRangeEnd'])) {
  1596.                         if (($hoardValues['hoardTerminalYearRangeStart'] == $initialSliderValues['hoardTerminalYearRangeStart'])
  1597.                             and ($hoardValues['hoardTerminalYearRangeEnd'] == $initialSliderValues['hoardTerminalYearRangeEnd'])) {
  1598.                             # Do nothing
  1599.                         } else {
  1600.                             $endKey "hoardTerminalYearRangeEnd";
  1601.                             $endValue $hoardValues['hoardTerminalYearRangeEnd'];
  1602.                             if (($hoardValues['hoardTerminalYearRangeStart'] > $initialSliderValues['hoardTerminalYearRangeStart'])
  1603.                                 and
  1604.                                ($hoardValues['hoardTerminalYearRangeEnd'] < $initialSliderValues['hoardTerminalYearRangeEnd'])) {
  1605.                                 $rangeCondition  ' (h.' 'terminalYear1' ' >= :' $key;
  1606.                                 $rangeCondition .=   ' AND h.' 'terminalYear1' ' <= :' $endKey;
  1607.                                 $rangeCondition .= ' )';
  1608.                                 $rangeCondition .= ' OR ';
  1609.                                 $rangeCondition .= ' (h.' 'terminalYear2' ' >= :' $key;
  1610.                                 $rangeCondition .=   '  AND h.' 'terminalYear2' ' <= :' $endKey;
  1611.                                 $rangeCondition .= ' )';
  1612.                                 $doctrineQueryBuilder->andWhere($rangeCondition);
  1613.                                 $queryParameters[$key] = $value;
  1614.                                 $queryParameters[$endKey] = $endValue;
  1615.                             } else if ($hoardValues['hoardTerminalYearRangeStart'] > $initialSliderValues['hoardTerminalYearRangeStart']) {
  1616.                                 $rangeCondition  ' h.' 'terminalYear1' ' >= :' $key;
  1617.                                 $rangeCondition .= ' OR ';
  1618.                                 $rangeCondition .= ' h.' 'terminalYear2' ' >= :' $key;
  1619.                                 $doctrineQueryBuilder->andWhere($rangeCondition);
  1620.                                 $queryParameters[$key] = $value;
  1621.                             } else if ($hoardValues['hoardTerminalYearRangeEnd'] < $initialSliderValues['hoardTerminalYearRangeEnd']) {
  1622.                                 $rangeCondition  ' h.' 'terminalYear1' ' <= :' $endKey;
  1623.                                 $rangeCondition .= ' OR ';
  1624.                                 $rangeCondition .= ' h.' 'terminalYear2' ' <= :' $endKey;
  1625.                                 $doctrineQueryBuilder->andWhere($rangeCondition);
  1626.                                 $queryParameters[$endKey] = $endValue;
  1627.                             }
  1628.                         }
  1629.                     } else {
  1630.                         if ($hoardValues['hoardTerminalYearRangeStart'] == $initialSliderValues['hoardTerminalYearRangeStart']) {
  1631.                             # Do nothing
  1632.                         } else {
  1633.                             $doctrineQueryBuilder->andWhere('h.' 'terminalYear1' ' = :' $key);
  1634.                             $queryParameters[$key] = $value;
  1635.                         }
  1636.                     }
  1637.                 } else if ($field == "openingYearRangeStart") {
  1638.                     if (isset($hoardValues['hoardOpeningYearRangeEnd'])) {
  1639.                         if (($hoardValues['hoardOpeningYearRangeStart'] == $initialSliderValues['hoardOpeningYearRangeStart'])
  1640.                             and ($hoardValues['hoardOpeningYearRangeEnd'] == $initialSliderValues['hoardOpeningYearRangeEnd'])) {
  1641.                             # Do nothing
  1642.                         } else {
  1643.                             $endKey "hoardOpeningYearRangeEnd";
  1644.                             $endValue $hoardValues['hoardOpeningYearRangeEnd'];
  1645.                             if (($hoardValues['hoardOpeningYearRangeStart'] > $initialSliderValues['hoardOpeningYearRangeStart'])
  1646.                                 and
  1647.                                ($hoardValues['hoardOpeningYearRangeEnd'] < $initialSliderValues['hoardOpeningYearRangeEnd'])) {
  1648.                                 $rangeCondition  ' (h.' 'openingYear1' ' >= :' $key;
  1649.                                 $rangeCondition .=   ' AND h.' 'openingYear1' ' <= :' $endKey;
  1650.                                 $rangeCondition .= ' )';
  1651.                                 $rangeCondition .= ' OR ';
  1652.                                 $rangeCondition .= ' (h.' 'openingYear2' ' >= :' $key;
  1653.                                 $rangeCondition .=   '  AND h.' 'openingYear2' ' <= :' $endKey;
  1654.                                 $rangeCondition .= ' )';
  1655.                                 $doctrineQueryBuilder->andWhere($rangeCondition);
  1656.                                 $queryParameters[$key] = $value;
  1657.                                 $queryParameters[$endKey] = $endValue;
  1658.                             } else if ($hoardValues['hoardOpeningYearRangeStart'] > $initialSliderValues['hoardOpeningYearRangeStart']) {
  1659.                                 $rangeCondition  ' h.' 'openingYear1' ' >= :' $key;
  1660.                                 $rangeCondition .= ' OR ';
  1661.                                 $rangeCondition .= ' h.' 'openingYear2' ' >= :' $key;
  1662.                                 $doctrineQueryBuilder->andWhere($rangeCondition);
  1663.                                 $queryParameters[$key] = $value;
  1664.                             } else if ($hoardValues['hoardOpeningYearRangeEnd'] < $initialSliderValues['hoardOpeningYearRangeEnd']) {
  1665.                                 $rangeCondition  ' h.' 'openingYear1' ' <= :' $endKey;
  1666.                                 $rangeCondition .= ' OR ';
  1667.                                 $rangeCondition .= ' h.' 'openingYear2' ' <= :' $endKey;
  1668.                                 $doctrineQueryBuilder->andWhere($rangeCondition);
  1669.                                 $queryParameters[$endKey] = $endValue;
  1670.                             }
  1671.                         }
  1672.                     } else {
  1673.                         if ($hoardValues['hoardOpeningYearRangeStart'] == $initialSliderValues['hoardOpeningYearRangeStart']) {
  1674.                             # Do nothing
  1675.                         } else {
  1676.                             $doctrineQueryBuilder->andWhere('h.' 'openingYear1' ' = :' $key);
  1677.                             $queryParameters[$key] = $value;
  1678.                         }
  1679.                     }
  1680.                 } else if ($field == "archaeologyContextDateRangeStart") {
  1681.                     if ($hoardValues['hoardArchaeologyContextDateRangeEnd']) {
  1682.                         if (($hoardValues['hoardArchaeologyContextDateRangeStart'] == $initialSliderValues['hoardArchaeologyContextDateRangeStart'])
  1683.                             and ($hoardValues['hoardArchaeologyContextDateRangeEnd'] == $initialSliderValues['hoardArchaeologyContextDateRangeEnd'])) {
  1684.                             # Do nothing
  1685.                         } else {
  1686.                             $endKey "hoardArchaeologyContextDateRangeEnd";
  1687.                             $endValue $hoardValues['hoardArchaeologyContextDateRangeEnd'];
  1688.                             if ($hoardValues['hoardArchaeologyContextDateRangeStart'] > $initialSliderValues['hoardArchaeologyContextDateRangeStart']) {
  1689.                                 $rangeCondition  ' (h.' 'archaeologyContextDate1' ' >= :' $key;
  1690.                                 $rangeCondition .=   ' AND h.' 'archaeologyContextDate1' ' <= :' $endKey;
  1691.                                 $rangeCondition .= ' )';
  1692.                                 $rangeCondition .= ' OR ';
  1693.                                 $rangeCondition .= ' (h.' 'archaeologyContextDate2' ' >= :' $key;
  1694.                                 $rangeCondition .=   '  AND h.' 'archaeologyContextDate2' ' <= :' $endKey;
  1695.                                 $rangeCondition .= ' )';
  1696.                                 $doctrineQueryBuilder->andWhere($rangeCondition);
  1697.                                 $queryParameters[$key] = $value;
  1698.                                 $queryParameters[$endKey] = $endValue;
  1699.                             } else {
  1700.                                 # just search on end date
  1701.                                 $rangeCondition  ' h.' 'archaeologyContextDate1' ' <= :' $endKey;
  1702.                                 $rangeCondition .= ' OR ';
  1703.                                 $rangeCondition .= ' h.' 'archaeologyContextDate2' ' <= :' $endKey;
  1704.                                 $doctrineQueryBuilder->andWhere($rangeCondition);
  1705.                                 $queryParameters[$endKey] = $endValue;
  1706.                             }
  1707.                         }
  1708.                     } else {
  1709.                         if ($hoardValues['hoardArchaeologyContextDateRangeStart'] == $initialSliderValues['hoardArchaeologyContextDateRangeStart']) {
  1710.                             # Do nothing
  1711.                         } else {
  1712.                             $doctrineQueryBuilder->andWhere('h.' 'archaeologyContextDate1' ' = :' $key);
  1713.                             $queryParameters[$key] = $value;
  1714.                         }
  1715.                     }
  1716.                 } else if ($field == "coinCountMin") {
  1717.                     $endKey "hoardCoinCountMax";
  1718.                     $endValue $hoardValues['hoardCoinCountMax'];
  1719.                     if (($hoardValues['hoardCoinCountMin'] == $initialSliderValues['hoardCoinCountMin'])
  1720.                         and ($hoardValues['hoardCoinCountMax'] == $initialSliderValues['hoardCoinCountMax'])) {
  1721.                         # Do nothing
  1722.                     } else {
  1723.                         $doctrineQueryBuilder->join('h.coinCount''coinCt');
  1724.                         $doctrineQueryBuilder->andWhere('coinCt.coinCount >= :' $key);
  1725.                         $queryParameters[$key] = $value;
  1726.                         if ($hoardValues['hoardCoinCountMax'] < $initialSliderValues['hoardCoinCountMax']) {
  1727.                             $doctrineQueryBuilder->andWhere('coinCt.coinCount <= :' $endKey);
  1728.                             $queryParameters[$endKey] = $endValue;
  1729.                         }
  1730.                     }
  1731.                 } else if ((in_array($field, array("discoveryYearRangeEnd""terminalYearRangeEnd""openingYearRangeEnd""archaeologyContextDateRangeEnd""coinCountMax")))) {
  1732.                     # skip
  1733.                 } else if ($field == "hoardValidatedByUser" && $this->getUser()) {
  1734.                     $doctrineQueryBuilder->andWhere('h.validatedByUser = :' $key);
  1735.                     $queryParameters[$key] = intval($value);
  1736.                 } else if ($field == "hoardValidatedByAdmin" && $this->userIsAdmin()) {
  1737.                     $doctrineQueryBuilder->andWhere('h.validatedByAdmin = :' $key);
  1738.                     $queryParameters[$key] = intval($value);
  1739.                 } else if ($field == "hoardCoinDataValidatedByUser" && $this->getUser()) {
  1740.                     $doctrineQueryBuilder->andWhere('h.coinDataValidatedByUser = :' $key);
  1741.                     $queryParameters[$key] = intval($value);
  1742.                 } else if ($field == "hoardCoinDataValidatedByAdmin" && $this->userIsAdmin()) {
  1743.                     $doctrineQueryBuilder->andWhere('h.coinDataValidatedByAdmin = :' $key);
  1744.                     $queryParameters[$key] = intval($value);
  1745.                 } else if ($field == "objectComment") {
  1746.                     $doctrineQueryBuilder->join('h.objects''objects')
  1747.                         ->andWhere('objects.comment LIKE :' $key);
  1748.                     $queryParameters[$key] = '%'.$value.'%';
  1749.                 } else if ($field == "objectType") {
  1750.                     $doctrineQueryBuilder->join('h.objects''objects')
  1751.                                         ->andWhere('objects.object LIKE :'.$key);
  1752.                     $queryParameters[$key] = $value.'%';
  1753.                 } else if ($field == "hasContainer") {
  1754.                     $doctrineQueryBuilder->andWhere('h.containers IS NOT EMPTY');
  1755.                 } else if ($field == "hasObject") {
  1756.                     $doctrineQueryBuilder->andWhere('h.objects IS NOT EMPTY');
  1757.                 } else if ($field == "hasImage") {
  1758.                     $doctrineQueryBuilder->andWhere('h.hoardImages IS NOT EMPTY');
  1759.                 } else if ($field == "hideWhat") {
  1760.                     $doctrineQueryBuilder->andWhere('h.' 'hideWhat' ' = :' $key);
  1761.                     $queryParameters[$key] = $value;
  1762.                 } else if ($field == "hideFrom") {
  1763.                     $doctrineQueryBuilder->andWhere('h.' 'hideFrom' ' = :' $key);
  1764.                     $queryParameters[$key] = $value;
  1765.                 } else if ($field == "hasObjectWithImage") {
  1766.                     $doctrineQueryBuilder->join('h.objects''o')
  1767.                                         ->andWhere('o.objectImages IS NOT EMPTY');
  1768.                 } else if ($field == "containerString") {
  1769.                     $doctrineQueryBuilder->join('h.containers''cont')
  1770.                         ->andWhere('cont.container LIKE :' $key);
  1771.                     $queryParameters[$key] = '%'.$value.'%';
  1772.                 } else if ($field == "containerComment") {
  1773.                     $doctrineQueryBuilder->join('h.containers''cont')
  1774.                         ->andWhere('cont.comment LIKE :' $key);
  1775.                     $queryParameters[$key] = '%'.$value.'%';
  1776.                 } else if ($field == "containerHasImage") {
  1777.                     $doctrineQueryBuilder->join('h.containers''cont')
  1778.                                         ->andWhere('cont.containerImages IS NOT EMPTY');
  1779.                 }
  1780.                 else {
  1781.                     if ($field == "containerMaterials") {
  1782.                         $object $field;
  1783.                         // $doctrineQueryBuilder->join('c.' . 'denominations', 'denomination_materials');
  1784.                         // $doctrineQueryBuilder->join('denomination_materials.material', 'materials');
  1785.                         $doctrineQueryBuilder->join('h.' 'containers''container_materials');
  1786.                         $doctrineQueryBuilder->join('container_materials.material''containerMaterials');
  1787.                         $field "id";
  1788.                     } else if ($field == "containerForms") {
  1789.                         $object $field;
  1790.                         $doctrineQueryBuilder->join('h.' 'containers''container_form');
  1791.                         $doctrineQueryBuilder->join('container_form.containerForm''containerForms');
  1792.                         $field "id";
  1793.                     } else if ($field == "objectMaterials") {
  1794.                         $object $field;
  1795.                         $doctrineQueryBuilder->join('h.' 'objects''object_materials');
  1796.                         $doctrineQueryBuilder->join('object_materials.material''objectMaterials');
  1797.                         $field "id";
  1798.                     } else if ($field == "reference") {
  1799.                         if (!$isHoardRefJoined) {
  1800.                             $doctrineQueryBuilder->join('h.' 'hoardReferences''hoard_references');
  1801.                             $isHoardRefJoined true;
  1802.                         }
  1803.                         $doctrineQueryBuilder->join('hoard_references.reference''hoardref');
  1804.                         $object 'hoardref';
  1805.                         $field "id";
  1806.                     } else if ($field == "reference_string") {
  1807.                         if (!$isHoardRefJoined) {
  1808.                             $doctrineQueryBuilder->join('h.' 'hoardReferences''hoard_references');
  1809.                             $isHoardRefJoined true;
  1810.                         }
  1811.                         $object 'hoard_references';
  1812.                         $field "reference_str";
  1813.                     }
  1814.                     if (is_array($value)) {
  1815.                         if(!isset($object)) {
  1816.                             $object 'h';
  1817.                         }
  1818.                         $fieldQuery "( ";
  1819.                         foreach ($value as $index => $val) {
  1820.                             if ($index 0) {
  1821.                                 $fieldQuery .= " OR ";
  1822.                             }
  1823.                             $fieldQuery .= $object '.' $field ' = :' $key "_" $index;
  1824.                             $queryParameters[$key "_" $index] = $val;
  1825.                         }
  1826.                         $fieldQuery .= " )";
  1827.                         $doctrineQueryBuilder->andWhere($fieldQuery);
  1828.                     } else {
  1829.                         if ($field == "reference_str") {
  1830.                             $doctrineQueryBuilder->andWhere($object '.' $field ' LIKE :' $key);
  1831.                             $queryParameters[$key] = '%'.$value.'%';
  1832.                             // this would allow users to use their own wildcards
  1833.                             // $val = str_replace("*", "%", $value);
  1834.                             // $val = str_replace("?", "_", $val);
  1835.                             // $queryParameters[$key] = $val;
  1836.                         } else {
  1837.                             $doctrineQueryBuilder->andWhere('h.' $field ' = :' $key);
  1838.                             $queryParameters[$key] = $value;
  1839.                         }
  1840.                     }
  1841.                 }
  1842.             }
  1843.             $activeTab 3;   // Set tab to Results tab
  1844.         }
  1845.         //ignore coin year range if set to initial values
  1846.         if(isset($coinValues['coinYearRangeStart']) && $coinValues['coinYearRangeStart'] == $initialSliderValues['coinYearRangeStart']) {
  1847.             unset($coinValues['coinYearRangeStart']);
  1848.         }
  1849.         
  1850.         if(isset($coinValues['coinYearRangeEnd']) && $coinValues['coinYearRangeEnd'] == $initialSliderValues['coinYearRangeEnd']) {
  1851.             unset($coinValues['coinYearRangeEnd']);
  1852.         }
  1853.         if (!empty($coinValues)) {
  1854.             $isCoinRefJoined false;
  1855.             foreach ($coinValues as $key => $value) {
  1856.                 $field lcfirst(substr($keystrlen('coin')));
  1857.                 $object "c";
  1858.                 $subTables = array("persons""reigns""denominations""mints""aspects");
  1859.                 if (in_array($field$subTables)) {
  1860.                     $object $field;
  1861.                     $doctrineQueryBuilder->join('c.' $field$object);
  1862.                     $field "id";
  1863.                 } else if ($field == "yearRangeStart") {
  1864.                     if(isset($coinValues['coinYearRangeEnd'])) {
  1865.                         if (($coinValues['coinYearRangeStart'] == $initialSliderValues['coinYearRangeStart'])
  1866.                             and ($coinValues['coinYearRangeEnd'] == $initialSliderValues['coinYearRangeEnd'])) {
  1867.                                 #do nothing
  1868.                         } else {
  1869.                             $endKey "coinYearRangeEnd";
  1870.                             $endValue $coinValues['coinYearRangeEnd'];
  1871.                             
  1872.                             if($coinValues['coinYearRangeStart'] > $initialSliderValues['coinYearRangeStart']) {
  1873.                                 $rangeCondition  ' (c.' 'startingDate' ' >= :' $key;
  1874.                                 $rangeCondition .= ' AND c.' 'startingDate' ' <= :' $endKey;
  1875.                                 $rangeCondition .= ' )';
  1876.                                 $rangeCondition .= ' OR ';
  1877.                                 $rangeCondition .= ' (c.' 'endingDate' ' >= :' $key;
  1878.                                 $rangeCondition .= ' AND c.' 'endingDate' ' <= :' $endKey;
  1879.                                 $rangeCondition .= ' )';
  1880.                                 $doctrineQueryBuilder->andWhere($rangeCondition);
  1881.                                 $queryParameters[$key] = $value;
  1882.                                 $queryParameters[$endKey] = $endValue;
  1883.                             } else {
  1884.                                 # just search on end date
  1885.                                 $rangeCondition  ' c.' 'startingDate' ' <= :' $endKey;
  1886.                                 $rangeCondition .= ' OR ';
  1887.                                 $rangeCondition .= ' c.' 'endingDate' ' <= :' $endKey;
  1888.                                 $doctrineQueryBuilder->andWhere($rangeCondition);
  1889.                                 $queryParameters[$endKey] = $endValue;
  1890.                             }
  1891.                         }
  1892.                     } else {
  1893.                         if ($coinValues['coinYearRangeStart'] == $initialSliderValues['coinYearRangeStart']) {
  1894.                             # Do nothing
  1895.                         } else {
  1896.                             $doctrineQueryBuilder->andWhere('c.' 'startingDate' ' = :' $key);
  1897.                             $queryParameters[$key] = $value;
  1898.                         }
  1899.                     }
  1900.                 } else if ($field == "materials") {
  1901.                     $object $field;
  1902.                     $doctrineQueryBuilder->join('c.' 'denominations''denomination_materials');
  1903.                     $doctrineQueryBuilder->join('denomination_materials.material''materials');
  1904.                     $field "id";
  1905.                 } else if ($field == "reference") {
  1906.                     $object 'coinRef';
  1907.                     if (!$isCoinRefJoined) {
  1908.                         $doctrineQueryBuilder->join('c.' 'coinReferences'$object);
  1909.                         $isCoinRefJoined true;
  1910.                     }
  1911.                     $field "reference";
  1912.                 } else if ($field == "referenceString") {
  1913.                     $object 'coinRef';
  1914.                     if (!$isCoinRefJoined) {
  1915.                         $doctrineQueryBuilder->join('c.' 'coinReferences'$object);
  1916.                         $isCoinRefJoined true;
  1917.                     }
  1918.                     $field "reference_str";
  1919.                 }
  1920.                 // materials is a special case as users only have the option to search for:
  1921.                 // "23" => "Gold", "22,31" => "Silver", "7,49,53" => "Bronze"
  1922.                 // material ids have to be converted vrom comma separated values to an array
  1923.                 if ($key == "coinMaterials") {
  1924.                     $value explode(","$value);
  1925.                 }
  1926.                 
  1927.                 if (is_array($value)) {
  1928.                     $fieldQuery "( ";
  1929.                     foreach ($value as $index => $val) {
  1930.                         if ($index 0) {
  1931.                             $fieldQuery .= " OR ";
  1932.                         }
  1933.                         $fieldQuery .= $object '.' $field ' = :' $key "_" $index;
  1934.                         $queryParameters[$key "_" $index] = $val;
  1935.                     }
  1936.                     $fieldQuery .= " )";
  1937.                     $doctrineQueryBuilder->andWhere($fieldQuery);
  1938.                 } else {
  1939.                     if ($field == "hasImage") {
  1940.                         $doctrineQueryBuilder->join('c.' 'coinImages''coin_images');
  1941.                         $doctrineQueryBuilder->andWhere('coin_images.deleted IS NULL');
  1942.                         //$queryParameters[$key] = $value;
  1943.                     } else {
  1944.                         if($field == 'yearRangeStart' || $field == 'yearRangeEnd') {
  1945.                             //this has already been handled
  1946.                         } elseif ($field == "reference_str") {
  1947.                             $doctrineQueryBuilder->andWhere($object '.' $field ' LIKE :' $key);
  1948.                             $val str_replace("*""%"$value);
  1949.                             $val str_replace("?""_"$val);
  1950.                             $queryParameters[$key] = $val;
  1951.                         } else {
  1952.                             // do a straight equality condition
  1953.                             $doctrineQueryBuilder->andWhere($object '.' $field ' = :' $key);
  1954.                             $queryParameters[$key] = $value;
  1955.                         }
  1956.                     }
  1957.                 }
  1958.            }
  1959.         }
  1960.     }
  1961.     // get different hoards based on query
  1962.     /**
  1963.      * Retrieves coordinates of the hoards from database based on query
  1964.      *
  1965.      * @Route("/ajax_hoard_locations", name="ajax_hoard_locations", methods={"GET"})
  1966.      */
  1967.     public function ajaxGetHoardLocationQuery(Request $request) {
  1968.         $search_type $request->query->get('search_type');
  1969.         $isCoinMintSearch false
  1970.         $isAuthenticated false;
  1971.         if ($this->getUser()) {
  1972.             $isAuthenticated true;
  1973.         }
  1974.         
  1975.         $searchHasCoinFields false;
  1976.         $initialSliderValues = array();
  1977.         $initialSliderValues['hoardDiscoveryYearRangeStart'] = $this->getMinDiscoveryDate();
  1978.         $initialSliderValues['hoardDiscoveryYearRangeEnd'] = $this->getMaxDiscoveryDate();
  1979.         $initialSliderValues['hoardTerminalYearRangeStart'] = $this->getMinTerminalDate();
  1980.         $initialSliderValues['hoardTerminalYearRangeEnd'] = $this->getMaxTerminalDate();
  1981.         $initialSliderValues['hoardOpeningYearRangeStart'] = $this->getMinOpeningDate();
  1982.         $initialSliderValues['hoardOpeningYearRangeEnd'] = $this->getMaxOpeningDate();
  1983.         $initialSliderValues['hoardArchaeologyContextDateRangeStart'] = $this->getMinArchaeologyContextDate();
  1984.         $initialSliderValues['hoardArchaeologyContextDateRangeEnd'] = $this->getMaxArchaeologyContextDate();
  1985.         $coinminmax $this->getMinMaxCoinDate();
  1986.         $initialSliderValues['coinYearRangeStart'] = $coinminmax['min1'];
  1987.         $initialSliderValues['coinYearRangeEnd'] = $coinminmax['max1'];
  1988.         $initialSliderValues['hoardCoinCountMin'] = 0;
  1989.         $initialSliderValues['hoardCoinCountMax'] = 100000;
  1990.       
  1991.         $em $this->getDoctrine()->getManager();
  1992.         if (isset($request->query->get('ox_hs')['rules']) && strlen($request->query->get('ox_hs')['rules'])) {
  1993.             // check if coin fields are included in the search set $searchHasCoinFields
  1994.             $rulesStr $request->query->get('ox_hs')['rules'];
  1995.             if ( strpos($rulesStr'"field":"coin') || strpos($rulesStr'"field":"c.') ) {
  1996.                 $searchHasCoinFields true;
  1997.             }
  1998.             $rules json_decode($rulesStrtrue);
  1999.             $doctrineQueryBuilder $this->buildQuery($rules$search_type$request->request->get('format'));
  2000.             $doctrineQueryBuilder->addSelect('h.id, h.findSpotLatitude, h.findSpotLongitude, h.findSpotName');
  2001.             if ($search_type == 'search-coins') {
  2002.                 $doctrineQueryBuilder->addSelect('c.quantity');
  2003.                 if (strpos($rulesStr'"field":"coinMints.id"')) {
  2004.                     $isCoinMintSearch true;
  2005.                     // if coin mint was searched and searching for coins
  2006.                     // add mint locations to the response
  2007.                     $doctrineQueryBuilder
  2008.                         ->addSelect('coinMints.id AS mintId, coinMints.mint, coinMints.latitude AS mintLatitude, coinMints.longitude AS mintLongitude');
  2009.                 }
  2010.             }
  2011.         } 
  2012.         else {
  2013.             foreach ($request->query->get('ox_hs') as $key => $value) {
  2014.                 // check if coin fields are included in the search set $searchHasCoinFields
  2015.                 if (substr$key0) === "coinYear") {
  2016.                     if ($value != $initialSliderValues[$key]) {
  2017.                         $searchHasCoinFields true;
  2018.                     }
  2019.                 } 
  2020.                 elseif (substr$key0) === "coin") {
  2021.                     if ($value && $value != "") {
  2022.                         $searchHasCoinFields true;
  2023.                     }
  2024.                 }
  2025.             }
  2026.             $doctrineQueryBuilder $em->createQueryBuilder();
  2027.             if ($search_type == 'search-coins') {
  2028.                 $doctrineQueryBuilder
  2029.                     ->from('OxHoardBundle:Coin''c')
  2030.                     ->leftJoin('c.hoard''h')
  2031.                     ->addSelect('c.id, c.quantity');
  2032.             } 
  2033.             else {
  2034.                 $doctrineQueryBuilder->select('h')
  2035.                     ->from('OxHoardBundle:Hoard''h')
  2036.                     ->leftJoin('h.coins''c');
  2037.             }
  2038.             $doctrineQueryBuilder->addSelect('h.id, h.findSpotLatitude, h.findSpotLongitude, h.findSpotName, h.validatedByUser')
  2039.                 ->distinct();
  2040.             $em->getFilters()->enable('softdeleteable');
  2041.             $currentYear date("Y");
  2042.             $activeTab 1;
  2043.             $hoardValues = array();
  2044.             $coinValues  = array();
  2045.             $queryParameters = array();
  2046.             if (!empty($request->query->get('ox_hs'))) {
  2047.                 $this->constructSearchQuery($request$doctrineQueryBuilder$activeTab,
  2048.                     $hoardValues$coinValues$queryParameters$initialSliderValues);
  2049.             }
  2050.             foreach ($queryParameters as $key => $value) {
  2051.                 $doctrineQueryBuilder->setParameter($key$value);
  2052.             }
  2053.             // if coin mint was searched and searching for coins
  2054.             if ($search_type == 'search-coins' && strpos($doctrineQueryBuilder->getDql(), "mints.id = :coinMints")) {
  2055.                 $isCoinMintSearch true;
  2056.                 // add mint locations to the response
  2057.                 $doctrineQueryBuilder
  2058.                     ->addSelect('mints.id AS mintId, mints.mint, mints.latitude AS mintLatitude, mints.longitude AS mintLongitude');
  2059.             }
  2060.         }
  2061.         
  2062.         if (!$isAuthenticated) {
  2063.             // public can only see hoards which are validated by the user,
  2064.             // and which are either not hidden, or don't have everything hidden
  2065.             $doctrineQueryBuilder
  2066.                 ->andWhere('(h.validatedByUser = true) AND (h.hideFrom = 3 OR h.hideWhat < 3 OR h.hideWhat IS NULL)')
  2067.                 ->andWhere('(h.hideLocation IS NULL OR h.hideLocation != 1)');
  2068.             // if coin fields are included in the search
  2069.             if ($searchHasCoinFields) {
  2070.                 // public can only see hoards with coins which are validated by the user,
  2071.                 // and which are either not hidden, or don't have anything hidden
  2072.                 $doctrineQueryBuilder->andWhere('(h.coinDataValidatedByUser = true) AND (h.hideFrom = 3 OR h.hideWhat IS NULL)');
  2073.             }
  2074.         }
  2075.         
  2076.         $doctrineQueryBuilderAllRows = clone $doctrineQueryBuilder;
  2077.         $boundary = isset($request->query->get('ox_hs')["boundary"]) ?
  2078.             $request->query->get('ox_hs')["boundary"] :
  2079.             null;
  2080.         $noCoOrds = [];
  2081.         $hasBoundary true;
  2082.         if (!$boundary || is_null($boundary)) {
  2083.             $hasBoundary false;
  2084.             $doctrineQueryBuilderNoCoOrds = clone $doctrineQueryBuilderAllRows;
  2085.             $doctrineQueryBuilderNoCoOrds
  2086.                 ->andWhere('h.findSpotLongitude IS NULL OR h.findSpotLatitude IS NULL');
  2087.             $doctrineQueryNoCoOrds $doctrineQueryBuilderNoCoOrds->getQuery();
  2088.             $noCoOrds $doctrineQueryNoCoOrds->getArrayResult();
  2089.             // Add countries to "No CoOrd" results, if present.
  2090.             foreach ($noCoOrds as &$noCoOrds_hoard) {
  2091.                 if ($noCoOrds_hoard['id']) {
  2092.                     $hoardEntity $em->getRepository('OxHoardBundle:Hoard')->find($noCoOrds_hoard['id']);
  2093.                     $countries $hoardEntity->getCountries();
  2094.                     foreach ($countries as $country) {
  2095.                         if (isset($noCoOrds_hoard['country'])) {
  2096.                             $noCoOrds_hoard['country'] .= ", " $country->getCountry();
  2097.                         }
  2098.                         else {
  2099.                             $noCoOrds_hoard['country'] = ", " $country->getCountry();
  2100.                         }
  2101.                     }
  2102.                 }
  2103.             }
  2104.         }
  2105.         $doctrineQueryBuilder
  2106.             ->andWhere('h.findSpotLatitude IS NOT NULL')
  2107.             ->andWhere('h.findSpotLongitude IS NOT NULL');
  2108.         // Add handling of boundaries set for maps.
  2109.         $boundary = isset($request->query->get('ox_hs')["boundary"]) ?
  2110.             $request->query->get('ox_hs')["boundary"] :
  2111.             null;
  2112.         if ($boundary) {
  2113.             $doctrineQueryBuilder->andWhere('ST_Contains(ST_GEOMFROMTEXT(\'Polygon((' $boundary '))\'), Point(h.findSpotLatitude, h.findSpotLongitude)) = true');
  2114.         }
  2115.         
  2116.         $doctrineQuery $doctrineQueryBuilder->getQuery();
  2117.         $doctrineQueryAllRows $doctrineQueryBuilderAllRows->getQuery();
  2118.         $searchedHoards $doctrineQuery -> getArrayResult();
  2119.         //
  2120.         $minTerminalYear $initialSliderValues['hoardTerminalYearRangeStart'];
  2121.         $maxTerminalYear $initialSliderValues['hoardTerminalYearRangeEnd'];
  2122.         $termYears = [];
  2123.         foreach ($searchedHoards as $hoard) {
  2124.             if (isset($hoard[0]["terminalYear1"])) {
  2125.                 $termYears[] = $hoard[0]["terminalYear1"];
  2126.             }
  2127.         }
  2128.         sort($termYears);
  2129.         $minTerminalYear = isset($termYears[0]) ? 
  2130.             $termYears[0] :
  2131.             $minTerminalYear;
  2132.         $maxTerminalYear = isset($termYears[count($termYears) - 1]) ? 
  2133.             $termYears[count($termYears) - 1] :
  2134.             $maxTerminalYear;
  2135.         $allSearchedHoards $doctrineQueryAllRows->getArrayResult();
  2136.         if ($search_type == "search-coins") {
  2137.             $totalPoints =  array_reduce($allSearchedHoards, function ($carry$item) {
  2138.                 if ($item['id'] && $item['findSpotName']) {
  2139.                     $carry += $item['quantity'];
  2140.                 }
  2141.                 return $carry;
  2142.             });
  2143.         } 
  2144.         else {
  2145.             $totalPoints count($allSearchedHoards);
  2146.         }
  2147.         return new JsonResponse(array(
  2148.             'data' => $searchedHoards,
  2149.             'terminalYears' => [
  2150.                 'min' => $minTerminalYear,
  2151.                 'max' => $maxTerminalYear,
  2152.             ],
  2153.             'searchType' => $search_type,
  2154.             'isAuthenticated' => $isAuthenticated,
  2155.             'totalPoints' => $totalPoints,
  2156.             'noCoOrds' => $noCoOrds,
  2157.             'boundary' => $hasBoundary,
  2158.             'isCoinMintSearch' => $isCoinMintSearch,
  2159.         ));
  2160.     }
  2161.     /**
  2162.      * Get all coins to use in charts
  2163.      *
  2164.      * @param Request $request
  2165.      * @Route("/coins_chart_ajax", name="coins_chart_get", methods={"GET"})
  2166.      */
  2167.     public function restGetCoinsChart(Request $requestPaginatorInterface $paginator)
  2168.     {
  2169.         // call the indexAction with the given request string
  2170.         $coins $this->indexAction($request$paginatortrue); 
  2171.         $allCoins = array();
  2172.         foreach ($coins as $coin) {
  2173.             $quantity $coin->getQuantity();
  2174.             $startingDate $coin->getStartingDate();
  2175.             $endingDate $coin->getEndingDate();
  2176.             $reigns $coin->getReigns();
  2177.             foreach($reigns as $reign) {
  2178.                 if ($startingDate || $endingDate ||
  2179.                     ($reign->getId() != 2191 && $reign->getId() != 242)) { // exclude reigns: Uncertain, Republic
  2180.                     array_push($allCoins, array(
  2181.                         'quantity' => $quantity count($reigns),
  2182.                         'startingDate' => $startingDate,
  2183.                         'endingDate' => $endingDate,
  2184.                         "reignStartDate" => $reign->getStartDate(),
  2185.                         "reignEndDate" => $reign->getEndDate()
  2186.                     ));
  2187.                 }
  2188.             }
  2189.         }
  2190.         return new JsonResponse($allCoins);
  2191.     }
  2192. }