src/OceanExpertBundle/Controller/DefaultController.php line 107

Open in your IDE?
  1. <?php
  2. namespace OceanExpertBundle\Controller;
  3. use Doctrine\ORM\AbstractQuery;
  4. use PhpOffice\PhpSpreadsheet\Spreadsheet;
  5. use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
  6. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  7. use Symfony\Component\HttpFoundation\JsonResponse;
  8. use Symfony\Component\HttpFoundation\Request;
  9. use Symfony\Component\HttpFoundation\Response;
  10. use Symfony\Component\Security\Core\Exception\AuthenticationException;
  11. use Symfony\Component\Security\Core\Security;
  12. use Symfony\Component\Security\Core\SecurityContextInterface;
  13. use Symfony\Component\HttpFoundation\ResponseHeaderBag;
  14. class DefaultController extends AbstractController
  15. {
  16.     /**
  17.      * @param Request $request
  18.      *
  19.      * @return Response
  20.      */
  21.     public function indexAction(Request $request): Response
  22.     {
  23.         // this should be handled already by nelmio_cors package
  24.         // see config/packages/nelmio_cors.yaml
  25.         // see https://github.com/iobis/web/issues/133
  26.         // header('Access-Control-Allow-Origin: *');
  27.         $session $request->getSession();
  28.         $authErrorKey Security::AUTHENTICATION_ERROR;
  29.         $lastUsernameKey Security::LAST_USERNAME;
  30.         // get the error if any (works with forward and redirect -- see below)
  31.         if ($request->attributes->has($authErrorKey)) {
  32.             $error $request->attributes->get($authErrorKey);
  33.         } elseif (null !== $session
  34.             && $session->has($authErrorKey)
  35.         ) {
  36.             $error $session->get($authErrorKey);
  37.             $session->remove($authErrorKey);
  38.         } else {
  39.             $error null;
  40.         }
  41.         if (!$error instanceof AuthenticationException) {
  42.             $error null// The value does not come from the security component.
  43.         }
  44.         // last username entered by the user
  45.         $lastUsername = (null === $session) ? '' $session->get($lastUsernameKey);
  46.         if ($request->attributes->has($authErrorKey)) {
  47.             $error $request->attributes->get($authErrorKey);
  48.         } elseif (null !== $session
  49.             && $session->has($authErrorKey)
  50.         ) {
  51.             $error $session->get($authErrorKey);
  52.             $session->remove($authErrorKey);
  53.         } else {
  54.             $error null;
  55.         }
  56.         if ($this->has('security.csrf.token_manager')) {
  57.             $csrfToken $this->get('security.csrf.token_manager')
  58.                 ->getToken('authenticate')
  59.                 ->getValue();
  60.         } else {
  61.             // BC for SF < 2.4
  62.             $csrfToken $this->has('form.csrf_provider')
  63.                 ? $this->get('form.csrf_provider')
  64.                     ->generateCsrfToken('authenticate')
  65.                 : null;
  66.         }
  67.         $indSeaAreas = array();
  68.         $instSeaAreas = array();
  69.         $subjects = array();
  70.         $instType = array();
  71.         $resultLname = array();
  72.         $countryList = array();
  73.         $instNameList = array();
  74.         $instCountryList = array();
  75.         $searchOptions['indSeas'] = $indSeaAreas;
  76.         $searchOptions['instSeas'] = $instSeaAreas;
  77.         $searchOptions['subjects'] = $subjects;
  78.         $searchOptions['instType'] = $instType;
  79.         $searchOptions['expertLname'] = $resultLname;
  80.         $searchOptions['countryNames'] = $countryList;
  81.         $searchOptions['instName'] = $instNameList;
  82.         $searchOptions['instCountryList'] = $instCountryList;
  83.         $noresult = array();
  84.         if (null !== $request->attributes->get('noresult')) {
  85.             $noresult['message'] = $request->attributes->get('noresult');
  86.             $noresult['query'] = $request->attributes->get('query');
  87.         }
  88.         return $this->render(
  89.             'index.html.twig',
  90.             array(
  91.                 'last_username' => $lastUsername,
  92.                 'error' => $error,
  93.                 'csrf_token' => $csrfToken,
  94.                 'searchOptions' => $searchOptions,
  95.                 'noresult' => $noresult,
  96.             )
  97.         );
  98.     }
  99.     /**
  100.      * show some stats about OE
  101.      * - number of experts
  102.      * - number of institutes
  103.      * - number of events
  104.      * - number of documents
  105.      *
  106.      * @return Response
  107.      */
  108.     public function statisticsAction(): Response
  109.     {
  110.         //get info about the countries
  111.         $countryInfo = array();
  112.         $countries $this->getDoctrine()
  113.             ->getManager()
  114.             ->getRepository('OceanExpertBundle:Countries')
  115.             ->findAll();
  116.         $data = array();
  117.         $em $this->getDoctrine()->getManager();
  118.         //info about the number of experts
  119.         $qb $em->createQueryBuilder();
  120.         $expr $qb->expr();
  121.         $qb->select(
  122.             'count(i.idInd)'
  123.         )->from(
  124.             'OceanExpertBundle:Indiv',
  125.             'i'
  126.         )->where(
  127.             'i.status = 1'
  128.         )->andWhere(
  129.             $expr->neq('i.deceased'1)
  130.         );
  131.         $data['countExperts'] = $qb->getQuery()->getSingleScalarResult();
  132.         //info about the number of experts per country
  133.         //this is done in 2 steps as we need those with their own address
  134.         //and those that use the address of their institute
  135.         $data['expertsPerCountry'] = $this->getExpertsPerCountry();
  136.         //info about the number of institutes
  137.         $qb $em->createQueryBuilder();
  138.         $qb->select('count(i.idInst)');
  139.         $qb->from('OceanExpertBundle:Institutions''i');
  140.         $qb->where('i.activated = 1');
  141.         $data['countInstitutes'] = $qb->getQuery()->getSingleScalarResult();
  142.         //info about the number of events
  143.         $qb $em->createQueryBuilder();
  144.         $qb->select('count(e.idEvent)');
  145.         $qb->from('OceanExpertBundle:Events''e');
  146.         $qb->where('e.status = 1');
  147.         $data['countEvents'] = $qb->getQuery()->getSingleScalarResult();
  148.         //info about the number of documents
  149.         $qb $em->createQueryBuilder();
  150.         $qb->select('count(d.idDoc)');
  151.         $qb->from('OceanExpertBundle:Documents''d');
  152.         $qb->where('d.approved = 1');
  153.         $data['countDocuments'] = $qb->getQuery()->getSingleScalarResult();
  154.         //get all the possible calendar groups
  155.         $sitesGroups $this->getDoctrine()
  156.             ->getRepository('OceanExpertBundle:Groups')
  157.             ->createQueryBuilder('g')
  158.             ->select('g.idGroup, g.groupname, g.description')
  159.             ->where('g.hasSite = 1')
  160.             ->orderBy('g.groupname''ASC')
  161.             ->getQuery()
  162.             ->getResult(AbstractQuery::HYDRATE_ARRAY);
  163.         $data['groups'] = $sitesGroups;
  164.         return $this->render(
  165.             'statistics.html.twig',
  166.             array(
  167.                 'data' => $data
  168.             )
  169.         );
  170.     }
  171.     /**
  172.      * show the disclaimer
  173.      *
  174.      * @return Response
  175.      */
  176.     public function disclaimerAction(): Response
  177.     {
  178.         return $this->render('Static/disclaimer.html.twig');
  179.     }
  180.     /**
  181.      * download the list of experts per country as CSV
  182.      *
  183.      * @return Response
  184.      **/
  185.     public function downloadExpertsPerCountryAction()
  186.     {
  187.         $expertsPerCountry $this->getExpertsPerCountry();
  188.         $response = new Response();
  189.         $response->headers->set('Content-Type''text/csv; charset=utf-8');
  190.         $response->headers->set(
  191.             'Content-Disposition',
  192.             'attachment; filename="experts_per_country.csv"'
  193.         );
  194.         $fp fopen('php://output''w');
  195.         fputcsv($fp, array('Country''Number of experts'));
  196.         foreach ($expertsPerCountry as $countryId => $expert ) {
  197.             fputcsv($fp, array($expert['countryName'], $expert['nrOfExperts']));
  198.         }
  199.         fclose($fp);
  200.         return $response;
  201.     }
  202.     /**
  203.      * create the json files that are needed to make the map on the homepage
  204.      * - experts
  205.      * - institutes
  206.      *
  207.      * @return Response
  208.      */
  209.     public function createMapJsonAction(): Response
  210.     {
  211.         $em $this->get('doctrine')->getManager();
  212.         $connection $em->getConnection();
  213.         $stmtInd $connection->prepare(
  214.             "SELECT (
  215.                 CASE 
  216.                     WHEN i.use_inst_addr = 1 
  217.                     THEN inst.country_code 
  218.                     ELSE i.country_code END
  219.             ) AS country_id  
  220.             FROM indiv i 
  221.             LEFT JOIN indiv_institution iinst ON i.id_ind = iinst.id_ind
  222.             LEFT JOIN institutions inst ON inst.id_inst = iinst.id_inst
  223.             WHERE i.status = 1
  224.             ORDER BY country_id ASC"
  225.         );
  226.         $stmtInd->execute();
  227.         $indiv $stmtInd->fetchAll();
  228.         $countries = array();
  229.         foreach ($indiv as $value) {
  230.             if ((trim($value['country_id']) != '')
  231.                 && ($value['country_id']) != 0
  232.             ) {
  233.                 $countries[] = $value['country_id'];
  234.             }
  235.         }
  236.         $count array_count_values($countries);
  237.         $statement $connection->prepare(
  238.             "SELECT 
  239.                 latitude, 
  240.                 longitude, 
  241.                 country, 
  242.                 id_country 
  243.             FROM countries"
  244.         );
  245.         $statement->execute();
  246.         $countryList $statement->fetchAll();
  247.         $countryData = array();
  248.         foreach ($countryList as $value) {
  249.             $countryData[$value['id_country']]['latitude'] = $value['latitude'];
  250.             $countryData[$value['id_country']]['longitude'] = $value['longitude'];
  251.             $countryData[$value['id_country']]['country'] = $value['country'];
  252.             if (!isset($count[$value['id_country']])) {
  253.                 $count[$value['id_country']] = 0;
  254.             }
  255.             $countryData[$value['id_country']]['count'] = $count[$value['id_country']];
  256.         }
  257.         //we want to put the files here
  258.         $filePath $this->get('kernel')->getProjectDir();
  259.         $filePath .= '/web/js/';
  260.         //make the experts json file
  261.         $fp fopen($filePath 'experts.json''w');
  262.         fwrite($fp"var experts = [");
  263.         fwrite($fpjson_encode($countryData));
  264.         fwrite($fp"]");
  265.         fclose($fp);
  266.         $statement $connection->prepare("
  267.             SELECT 
  268.                    latitude, 
  269.                    longitude, 
  270.                    country, 
  271.                    count(*) AS count 
  272.             FROM institutions 
  273.                 LEFT JOIN countries ON institutions.country_code = countries.id_country 
  274.             WHERE activated = 1 
  275.               AND country IS NOT NULL 
  276.             GROUP BY country");
  277.         $statement->execute();
  278.         $countryList $statement->fetchAll();
  279.         $fp fopen($filePath 'institutes.json''w');
  280.         fwrite($fp"var institutes = [");
  281.         fwrite($fpjson_encode($countryList));
  282.         fwrite($fp"]");
  283.         fclose($fp);
  284.         $response "Generated <a href='/js/experts.json'>experts.json</a> and <a href='/js/institutes.json'>institutes.json</a>";
  285.         return new Response($response);
  286.     }
  287.     /**
  288.      * create the custom report using the given parameters
  289.      *
  290.      * @param Request $request
  291.      *
  292.      * @return Response
  293.      */
  294.     public function customReportAction(Request $request): Response
  295.     {
  296.         // request contains:
  297.         //startDate, endDate, groupsselect
  298.         $params $request->request->all();
  299.         //dump($params['startDate']);
  300.         //dump($params['endDate']);
  301.         //dump($params['groupsselect']);
  302.         //get all the events that match the given parameters
  303.         $events $this->getDoctrine()->getRepository('OceanExpertBundle:Events')
  304.             ->createQueryBuilder('e')
  305.             ->select('e.idEvent, 
  306.                 e.startOn, 
  307.                 e.endOn, 
  308.                 et.eventtypeName AS eventType,
  309.                 e.title'
  310.             )
  311.             ->leftJoin(
  312.                 'OceanExpertBundle:EventGroups',
  313.                 'eg',
  314.                 'WITH',
  315.                 'e.idEvent = eg.idEvent'
  316.             )
  317.             ->leftJoin(
  318.                 'OceanExpertBundle:Eventtypes',
  319.                 'et',
  320.                 'WITH',
  321.                 'e.idEventtype = et.idEventtype'
  322.             )
  323.             ->distinct();
  324.             //->where('1');
  325.         if (
  326.             isset($params['startDate'])
  327.             && $params['startDate'] != ''
  328.         ) {
  329.             $events->andWhere('e.startOn >= :startDate')
  330.                 ->setParameter('startDate'$params['startDate']);
  331.         }
  332.         if (
  333.             isset($params['endDate'])
  334.             && $params['endDate'] != ''
  335.         ) {
  336.             $events->andWhere('e.startOn <= :endDate')
  337.                 ->setParameter('endDate'$params['endDate']);
  338.         }
  339.         if (
  340.             isset($params['idGroup'])
  341.             && $params['idGroup'] != ''
  342.         ) {
  343.             $events->andWhere('eg.idGroup = :idGroup')
  344.                 ->setParameter('idGroup'$params['idGroup']);
  345.         }
  346.         $events->orderBy('e.startOn''ASC');
  347.         //dump($events->getQuery());
  348.         $events $events->getQuery()->getResult(AbstractQuery::HYDRATE_ARRAY);
  349.         //dump($events);
  350.         //die();
  351.         //get all the countries
  352.         $countries $this->getDoctrine()
  353.             ->getManager()
  354.             ->getRepository('OceanExpertBundle:Countries')
  355.             ->findAll();
  356.         //we don't need all the info, just id id_country and country
  357.         $countries array_reduce(
  358.             $countries,
  359.             function ($result$country) {
  360.                 $result[$country->getIdCountry()] = array(
  361.                     'country' => $country->getCountry(),
  362.                     'countryCode' => $country->getCountryCode()
  363.                 );
  364.                 return $result;
  365.             },
  366.             array()
  367.         );
  368.         //dump($countries);
  369.         //make an excel file with the participants per event
  370.         $spreadsheet = new Spreadsheet();
  371.         $sheet $spreadsheet->getActiveSheet();
  372.         $sheet->setTitle('OceanExpert Custom Report');
  373.         $sheet->setCellValue('A1''event title');
  374.         $sheet->setCellValue('B1''event type');
  375.         $sheet->setCellValue('C1''starts on');
  376.         $sheet->setCellValue('D1''ends on');
  377.         $sheet->setCellValue('E1''first name');
  378.         $sheet->setCellValue('F1''surname');
  379.         $sheet->setCellValue('G1''gender');
  380.         $sheet->setCellValue('H1''nationality');
  381.         $sheet->setCellValue('I1''work location/country');
  382.         $sheetRow 2;
  383.         //get all the participants of the events
  384.         foreach ($events as $keyEvents => $event) {
  385.             //dump($event);
  386.             $idEvent $event['idEvent'];
  387.             //dump($idEvent);
  388.             $participants $this->getDoctrine()->getRepository('OceanExpertBundle:Indiv')
  389.                 ->createQueryBuilder('i')
  390.                 ->select('
  391.                     i.idInd, 
  392.                     i.fname, 
  393.                     i.sname,
  394.                     i.gender,
  395.                     i.idNationality,
  396.                     i.useInstAddr,
  397.                     i.countryCode,
  398.                     ii.idInst'
  399.                 )
  400.                 ->leftJoin(
  401.                     'OceanExpertBundle:EventParticipants',
  402.                     'ep',
  403.                     'WITH',
  404.                     'i.idInd = ep.idInd'
  405.                 )
  406.                 ->leftJoin(
  407.                     'OceanExpertBundle:IndivInstitution',
  408.                     'ii',
  409.                     'WITH',
  410.                     'i.idInd = ii.idInd'
  411.                 )
  412.                 ->where('ep.idEvent = :idEvent')
  413.                 ->setParameter('idEvent'$idEvent)
  414.                 ->getQuery()
  415.                 ->getResult(AbstractQuery::HYDRATE_ARRAY);
  416.             //cleanup the data
  417.             //dump($participants);
  418.             //die();
  419.             foreach ($participants as $key => $participant) {
  420.                 //this info is the same for all participants of this event
  421.                 $sheet->setCellValue('A' $sheetRow$event['title']);
  422.                 $sheet->setCellValue('B' $sheetRow$event['eventType']);
  423.                 $sheet->setCellValue('C' $sheetRow$event['startOn']->format('Y-m-d'));
  424.                 $sheet->setCellValue('D' $sheetRow$event['endOn']->format('Y-m-d'));
  425.                 //add the country name to the participant
  426.                 if (isset($participant['idNationality'])) {
  427.                     //experts can have more than one nationality
  428.                     $nationalities explode(','$participant['idNationality']);
  429.                     $finalNationalities = array();
  430.                     foreach ($nationalities as $nationality) {
  431.                         if (isset($countries[$nationality])) {
  432.                             $finalNationalities[] = $countries[$nationality]['country'];
  433.                         } else {
  434.                             $finalNationalities[] = 'wrong value';
  435.                         }
  436.                     }
  437.                     $nationality implode(','$finalNationalities);
  438.                 } else {
  439.                     //should not happen, but just in case
  440.                     $nationality 'unknown';
  441.                 }
  442.                 //add the workaddress/country name to the participant
  443.                 if (isset($participant['countryCode'])
  444.                     && $participant['useInstAddr'] != 1
  445.                     && isset($countries[$participant['countryCode']])
  446.                 ) {
  447.                     $workAddressCountry $countries[$participant['countryCode']]['country'];
  448.                 } elseif(isset($participant['countryCode'])
  449.                     && $participant['useInstAddr'] == 1
  450.                     && $participant['idInst'] != null
  451.                 ) {
  452.                     $inst $this->getDoctrine()
  453.                         ->getRepository('OceanExpertBundle:Institutions')
  454.                         ->find($participant['idInst']);
  455.                     if ($inst
  456.                         && $inst->getCountryCode() != null
  457.                     ){
  458.                         $workAddressCountry $countries[$inst->getCountryCode()]['country'];;
  459.                     } else {
  460.                         //should not happen, but just in case
  461.                         $workAddressCountry 'unknown institute country';
  462.                     }
  463.                 } else {
  464.                     //should not happen, but just in case
  465.                     $workAddressCountry 'unknown';
  466.                 }
  467.                 //this is info specific for the participant
  468.                 $sheet->setCellValue('E' $sheetRow$participant['fname']);
  469.                 $sheet->setCellValue('F' $sheetRow$participant['sname']);
  470.                 $sheet->setCellValue('G' $sheetRow$participant['gender']);
  471.                 $sheet->setCellValue('H' $sheetRow$nationality);
  472.                 $sheet->setCellValue('I' $sheetRow$workAddressCountry);
  473.                 $sheetRow ++;
  474.                 unset($participants[$key]);
  475.             }
  476.             unset($events[$keyEvents]);
  477.             //dump($participants);
  478.         }
  479.         // Create your Office 2007 Excel (XLSX Format)
  480.         $writer = new Xlsx($spreadsheet);
  481.         // Create a Temporary file in the system
  482.         $fileName 'OceanExpertCustomReport.xlsx';
  483.         $temp_file tempnam(sys_get_temp_dir(), $fileName);
  484.         // Create the excel file in the tmp directory of the system
  485.         $writer->save($temp_file);
  486.         // Return the excel file as an attachment
  487.         return $this->file(
  488.             $temp_file,
  489.             $fileName,
  490.             ResponseHeaderBag::DISPOSITION_INLINE
  491.         );
  492.     }
  493.     /**
  494.      * give the number of experts per searegion
  495.      *
  496.      * @return JsonResponse
  497.      */
  498.     public function getExpertsSeaRegionsAction(): JsonResponse
  499.     {
  500.         $repository $this->getDoctrine()->getRepository('OceanExpertBundle:Indiv');
  501.         $seaRegionsInd $repository->createQueryBuilder('i')
  502.             ->select('DISTINCT i.studyregion')
  503.             ->getQuery()
  504.             ->getResult();
  505.         $seaRegions = array();
  506.         foreach ($seaRegionsInd as $value) {
  507.             foreach (explode(','$value['studyregion']) as $item) {
  508.                 if (is_numeric($item)) {
  509.                     $seaRegions[] = trim($this->getRegionById($item));
  510.                 }
  511.             }
  512.         }
  513.         $seaRegions array_unique($seaRegions);
  514.         $allSeas $this->getDoctrine()
  515.             ->getManager()
  516.             ->getRepository('OceanExpertBundle:Searegions')
  517.             ->findBy(
  518.                 [],
  519.                 ['name' => 'ASC']
  520.             );
  521.         $availableSeas = array();
  522.         foreach ($allSeas as $value) {
  523.             $availableSeas[$value->getIdSearegion()] = $value->getName();
  524.         }
  525.         $indSeaAreas array_intersect(
  526.             $availableSeas,
  527.             $seaRegions
  528.         );
  529.         return new JsonResponse($indSeaAreas);
  530.     }
  531.     /**
  532.      * give the name of a region using the id
  533.      *
  534.      * @param int $id id of the region
  535.      *
  536.      * @return string
  537.      */
  538.     public function getRegionById(int $id): string
  539.     {
  540.         $region $this->getDoctrine()
  541.             ->getRepository('OceanExpertBundle:Searegions')
  542.             ->findOneBy(array('idSearegion' => $id));
  543.         if ($region) {
  544.             return $region->getName();
  545.         } else {
  546.             return '';
  547.         }
  548.     }
  549.     /**
  550.      * @return JsonResponse
  551.      */
  552.     function getInstitutesSeaRegionsAction(): JsonResponse
  553.     {
  554.         $repository $this->getDoctrine()
  555.             ->getRepository('OceanExpertBundle:Institutions');
  556.         $seaRegionsInst $repository->createQueryBuilder('i')
  557.             ->select('DISTINCT i.instRegion')
  558.             ->getQuery()
  559.             ->getResult(AbstractQuery::HYDRATE_ARRAY);
  560.         $seaRegions = array();
  561.         foreach ($seaRegionsInst as $value) {
  562.             foreach (explode(','$value['instRegion']) as $item) {
  563.                 if (trim($item) != '') {
  564.                     array_push($seaRegionstrim($item));
  565.                 }
  566.             }
  567.         }
  568.         $seaRegions array_unique($seaRegions);
  569.         $repository $this->getDoctrine()->getRepository('OceanExpertBundle:Searegions');
  570.         $instSeaAreas $repository->createQueryBuilder('r')
  571.             ->select('r.idSearegion, r.name')
  572.             ->where('r.idSearegion IN(:seaRegions) ')
  573.             ->setParameter('seaRegions'array_values($seaRegions))
  574.             ->getQuery()->getResult();
  575.         return new JsonResponse($instSeaAreas);
  576.     }
  577.     /**
  578.      * @return JsonResponse
  579.      */
  580.     function getExpertsSubjectsAction(): JsonResponse
  581.     {
  582.         $subjects $this->getDoctrine()
  583.             ->getRepository('OceanExpertBundle:Subjects')
  584.             ->createQueryBuilder('s')
  585.             ->select('s.subname, s.idSub')
  586.             ->orderBy('s.subname''ASC')
  587.             ->getQuery()
  588.             ->getResult(AbstractQuery::HYDRATE_ARRAY);
  589.         return new JsonResponse($subjects);
  590.     }
  591.     /**
  592.      * get all possible first letters of the experts names
  593.      *
  594.      * @return JsonResponse
  595.      */
  596.     function getExpertsLastNameAction(): JsonResponse
  597.     {
  598.         $em $this->getDoctrine()->getManager();
  599.         $connection $em->getConnection();
  600.         $statement $connection->prepare("SELECT DISTINCT 
  601.                 UPPER(LEFT(sname, 1)) AS letter 
  602.             FROM indiv 
  603.             ORDER BY letter"
  604.         );
  605.         $statement->execute();
  606.         $lnameList $statement->fetchAll();
  607.         $resultLname array_column($lnameList'letter');
  608.         return new JsonResponse($resultLname);
  609.     }
  610.     /**
  611.      * @return JsonResponse
  612.      */
  613.     function getExpertCountryListAction(): JsonResponse
  614.     {
  615.         $em $this->getDoctrine()->getManager();
  616.         $connection $em->getConnection();
  617.         $statement $connection->prepare("
  618.             SELECT DISTINCT 
  619.                 UPPER(LEFT(country, 1)) AS letter 
  620.             FROM countries 
  621.             WHERE id_country IN (SELECT DISTINCT(country_code) FROM indiv) 
  622.             ORDER BY letter"
  623.         );
  624.         $statement->execute();
  625.         $countries $statement->fetchAll();
  626.         $countryList array_column($countries'letter');
  627.         return new JsonResponse($countryList);
  628.     }
  629.     /**
  630.      * get the list of institution types
  631.      *
  632.      * @todo : check if this is still needed, same functionality is available in the SearchController
  633.      *
  634.      * @return JsonResponse
  635.      */
  636.     function getInstitutionTypesAction(): JsonResponse
  637.     {
  638.         $instType $this->getDoctrine()
  639.             ->getRepository('OceanExpertBundle:Insttypes')
  640.             ->createQueryBuilder('i')
  641.             ->select('i.insttypeName, i.idInsttype')
  642.             ->orderBy('i.insttypeName''ASC')
  643.             ->getQuery()
  644.             ->getResult(AbstractQuery::HYDRATE_ARRAY);
  645.         return new JsonResponse($instType);
  646.     }
  647.     /**
  648.      * @return JsonResponse
  649.      */
  650.     function getInstitutionNameListAction(): JsonResponse
  651.     {
  652.         $em $this->getDoctrine()->getManager();
  653.         $connection $em->getConnection();
  654.         $statement $connection->prepare(
  655.             "SELECT DISTINCT 
  656.                 UPPER(LEFT(inst_name, 1)) AS letter 
  657.             FROM institutions 
  658.             ORDER BY letter"
  659.         );
  660.         $statement->execute();
  661.         $institutes $statement->fetchAll();
  662.         $instNameList array_column($institutes'letter');
  663.         return new JsonResponse($instNameList);
  664.     }
  665.     /**
  666.      * @return JsonResponse
  667.      */
  668.     function getInstitutionCountryListAction(): JsonResponse
  669.     {
  670.         $em $this->getDoctrine()->getManager();
  671.         $connection $em->getConnection();
  672.         $statement $connection->prepare(
  673.             "SELECT DISTINCT 
  674.                 UPPER(LEFT(country, 1)) AS letter 
  675.             FROM countries 
  676.             WHERE id_country IN (SELECT DISTINCT(country_code) 
  677.             FROM institutions) 
  678.             ORDER BY letter"
  679.         );
  680.         $statement->execute();
  681.         $instCountries $statement->fetchAll();
  682.         $instCountryList array_column($instCountries'letter');
  683.         return new JsonResponse($instCountryList);
  684.     }
  685.     /**
  686.      * make a list of the number of experts per country
  687.      *
  688.      * @return array
  689.      */
  690.     private function getExpertsPerCountry()
  691.     {
  692.         //get info about the countries
  693.         $countryInfo = array();
  694.         $countries $this->getDoctrine()
  695.             ->getManager()
  696.             ->getRepository('OceanExpertBundle:Countries')
  697.             ->findAll();
  698.         $returnValue = array();
  699.         $em $this->getDoctrine()->getManager();
  700.         //step 1 : those with their own address
  701.         $qb $em->createQueryBuilder();
  702.         $expr $qb->expr();
  703.         $qb->select(
  704.             "count('i.idInd') AS nr",
  705.             'c.country'
  706.         )->from(
  707.             'OceanExpertBundle:Indiv',
  708.             'i'
  709.         )->leftJoin(
  710.             'OceanExpertBundle:Countries',
  711.             'c',
  712.             'WITH',
  713.             'i.countryCode = c.idCountry'
  714.         )->where(
  715.             'i.status = 1'
  716.         )->andWhere(
  717.             $expr->neq('i.deceased'1)
  718.         )->andWhere(
  719.             $expr->neq('i.retired'1)
  720.         )->andWhere(
  721.             $expr->neq('i.useInstAddr'1)
  722.         )->andWhere(
  723.             'c.idCountry IS NOT NULL'
  724.         )->groupBy(
  725.             'i.countryCode'
  726.         );
  727.         $experts $qb->getQuery()->getResult(AbstractQuery::HYDRATE_ARRAY);
  728.         foreach ($experts as $expert) {
  729.             $expertsPerCountry[$expert['country']] = intval($expert['nr']);
  730.         }
  731.         //step 2 : those that use the address of their institute
  732.         $qb $em->createQueryBuilder();
  733.         $expr $qb->expr();
  734.         $qb->select(
  735.             "count('i.idInd') AS nr",
  736.             'c.country'
  737.         )->from(
  738.             'OceanExpertBundle:Indiv',
  739.             'i'
  740.         )->leftJoin(
  741.             'OceanExpertBundle:IndivInstitution',
  742.             'ii',
  743.             'WITH',
  744.             'i.idInd = ii.idInd'
  745.         )->leftJoin(
  746.             'OceanExpertBundle:Institutions',
  747.             'inst',
  748.             'WITH',
  749.             'ii.idInst = inst.idInst'
  750.         )->leftJoin(
  751.             'OceanExpertBundle:Countries',
  752.             'c',
  753.             'WITH',
  754.             'inst.countryCode = c.idCountry'
  755.         )->where(
  756.             'i.status = 1'
  757.         )->andWhere(
  758.             $expr->neq('i.deceased'1)
  759.         )->andWhere(
  760.             $expr->neq('i.retired'1)
  761.         )->andWhere(
  762.             'i.useInstAddr = 1'
  763.         )->andWhere(
  764.             'c.idCountry IS NOT NULL'
  765.         )->groupBy(
  766.             'inst.countryCode'
  767.         );
  768.         $experts $qb->getQuery()->getResult(AbstractQuery::HYDRATE_ARRAY);
  769.         foreach ($experts as $expert) {
  770.             $expertsPerInstCountry[$expert['country']] = intval($expert['nr']);
  771.         }
  772.         foreach ($countries as $country) {
  773.             $countryId $country->getIdCountry();
  774.             $countryName $country->getCountry();
  775.             $countryCode $country->getCountryCode();
  776.             $nrOfExperts 0;
  777.             if (isset($expertsPerCountry[$countryName])) {
  778.                 $nrOfExperts += $expertsPerCountry[$countryName];
  779.             }
  780.             if (isset($expertsPerInstCountry[$countryName])) {
  781.                 $nrOfExperts += $expertsPerInstCountry[$countryName];
  782.             }
  783.             $returnValue[$countryId]['nrOfExperts'] = $nrOfExperts;
  784.             $returnValue[$countryId]['countryName'] = $countryName;
  785.             $returnValue[$countryId]['countryId'] = $countryId;
  786.             $returnValue[$countryId]['countryCode'] = $countryCode;
  787.         }
  788.         ksort($returnValue);
  789.         return $returnValue;
  790.     }
  791. }