src/Ox/HoardBundle/Controller/HoardController.php line 346

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 App\Ox\HoardBundle\Entity\Hoard;
  17. use App\Ox\HoardBundle\Entity\HObject;
  18. use App\Ox\HoardBundle\Entity\Coin;
  19. use App\Ox\HoardBundle\Entity\Container;
  20. use App\Ox\HoardBundle\Entity\HoardCoinCount;
  21. use App\Ox\HoardBundle\Entity\HoardImage;
  22. use App\Ox\HoardBundle\Form\HoardType;
  23. use App\Ox\HoardBundle\Form\HoardSearchType;
  24. use App\Ox\HoardBundle\Form\SummaryCoinType;
  25. use App\Ox\HoardBundle\Form\SearchType;
  26. use SimpleThings\EntityAudit\AuditConfiguration;
  27. use SimpleThings\EntityAudit\AuditManager;
  28. /**
  29.  * Hoard controller.
  30.  *
  31.  * @Route("/hoard")
  32.  */
  33. class HoardController extends AbstractController
  34. {
  35.     private $security;
  36.     public function __construct(Security $security)
  37.     {
  38.         $this->security $security;
  39.     }
  40.     /**
  41.      * creates csv and appropriate page response for csv of supplied query
  42.      *
  43.      */
  44.     private function outputCSV(Array $data$prefix=null$exportCoins=false$refData=null) {
  45.         if($prefix == null) {
  46.             $prefix "export";
  47.         }
  48.         $filename $prefix."_".date("Y_m_d_His").".csv";
  49.         if($exportCoins) {
  50.             //build an array of column headings for the reference columns
  51.             if($refData) {
  52.                 $refHeadings = [];
  53.                 foreach($refData['own_column_references'] as $o_c_ref) {
  54.                     if(isset($o_c_ref['abbreviation'])) {
  55.                         $refHeadings[] = $o_c_ref['abbreviation'] . ' Reference';
  56.                     } else {
  57.                         $refHeadings[] = $o_c_ref['title'] . ' Reference';
  58.                     }
  59.                 }
  60.                 for($i=1$i <= $refData['num_other_references']; $i++) {
  61.                     $refHeadings[] = 'Other Reference '.$i;
  62.                 }
  63.             }
  64.             $response $this->render('@OxHoardBundle/coin/csvExport.html.twig', array(
  65.                                             'data' => $data,
  66.                                             // 'numRefs' => 10,
  67.                                             'ref_headings' => $refHeadings,
  68.                                             'num_ref_columns' => count($refHeadings)
  69.                                         ));
  70.         } else {
  71.             $response $this->render('@OxHoardBundle/hoard/csvExport.html.twig', array(
  72.                 'is_authenticated' => !!$this->getUser(),
  73.                 'data' => $data
  74.             ));
  75.         }
  76.         
  77.         $response->headers->set('Content-Type''text/csv');
  78.         $response->setStatusCode(200);
  79.         $response->setCharset('UTF-8');
  80.         $response->headers->set('Content-Type''text/csv');
  81.         $response->headers->set('Content-Description''Hoards Export');
  82.         $response->headers->set('Content-Disposition''attachment; filename='.$filename);
  83.         $response->headers->set('Content-Transfer-Encoding''binary');
  84.         $response->headers->set('Pragma''no-cache');
  85.         $response->headers->set('Expires''0');
  86.         return $response;
  87.      }
  88.     /**
  89.      * Creates a new Hoard entity.
  90.      *
  91.      * @Route("/create", name="hoard_create", methods={"POST"})
  92.      * @Template("@OxHoardBundle/hoard/new.html.twig")
  93.      */
  94.     public function createAction(Request $request)
  95.     {
  96.         //only logged in users can create
  97.         if(!$this->getUser()) {
  98.             throw new AccessDeniedException("Only logged in contributors may create a hoard entry");
  99.         }
  100.         $entity = new Hoard();
  101.         $form $this->createCreateForm($entity);
  102.         $form->handleRequest($request);
  103.         if ($form->isValid()) {
  104.             $em $this->getDoctrine()->getManager();
  105.             $em->persist($entity);
  106.             //persist the hoardImages
  107.             $hoardImages $entity->getHoardImages();
  108.             foreach ($hoardImages as $hoardImage)
  109.                 if (!$hoardImage->getDeleted()) {
  110.                     $em->persist($hoardImage);
  111.                 }
  112.             //persist references
  113.             $hoardReferences $entity->getHoardReferences();
  114.             foreach ($hoardReferences as $reference) {
  115.                 if (!$reference->getDeleted()) {
  116.                     $reference->setHoard($entity);
  117.                     $em->persist($reference);
  118.                 }
  119.             }
  120.             
  121.             $entity->setCreated($this->getUser());
  122.             $entity->setModified($this->getUser());
  123.             $this->addRelatedCountries($entity);
  124.             $em->flush();
  125.         }
  126.         return $this->redirect($this->generateUrl('hoard_show',
  127.             array(
  128.                 'id' => $entity->getId(),
  129.             )
  130.         ));
  131.     }
  132.     /**
  133.      * Creates a form to create a Hoard entity.
  134.      *
  135.      * @param Hoard $entity The entity
  136.      *
  137.      * @return \Symfony\Component\Form\Form The form
  138.      */
  139.     private function createCreateForm(Hoard $entity)
  140.     {
  141.         $formOptions = array(
  142.             'action' => $this->generateUrl('hoard_create'),
  143.             'method' => 'POST',
  144.             'em' => $this->getDoctrine()->getManager(),
  145.         );
  146.         if(!$this->userIsAdmin()) {
  147.             $formOptions['countries'] = $this->getUser()->getAccessibleCountries();
  148.         }
  149.         $form $this->createForm(HoardType::class, $entity$formOptions);
  150.         if($this->userIsAdmin())
  151.         {
  152.             $form->add('validatedByAdmin');
  153.         }
  154.         $form->add('submit'SubmitType::class, array('label' => 'Create'));
  155.         return $form;
  156.     }
  157.     /**
  158.      * Displays a form to create a new Hoard entity.
  159.      *
  160.      * @Route("/new", name="hoard_new", methods={"GET"})
  161.      * @Template()
  162.      */
  163.     public function newAction()
  164.     {
  165.         //only logged in users can create
  166.         if(!$this->getUser()) {
  167.             throw new AccessDeniedException("Only logged in contributors may create a hoard entry");
  168.         }
  169.         $hoard = new Hoard();
  170.         $form   $this->createCreateForm($hoard);
  171.         $coinAddForm $this->createForm(SummaryCoinType::class, null, array());
  172.         $object_prototype = array(
  173.             'id' => '__id__',
  174.             'object' => '',
  175.             'description' => '',
  176.         );
  177.         $container_prototype = array(
  178.             'id' => '__id__',
  179.             'container' => '',
  180.             'comment' => ''
  181.         );
  182.         $em $this->getDoctrine()->getManager();
  183.         $referenceTypes $em->createQuery('SELECT rt FROM OxHoardBundle:ReferenceType rt ORDER BY rt.sortValue DESC, rt.referenceType ASC')->getResult();
  184.         return $this->render('@OxHoardBundle/hoard/edit.html.twig', array(
  185.             'object_proto' => $object_prototype,
  186.             'container_proto' => $container_prototype,
  187.             'hoard' => $hoard,
  188.             'images' => array(),
  189.             'coin_data' => array(),
  190.             'coin_add_form' => $coinAddForm->createView(),
  191.             'edit_form'   => $form->createView(),
  192.             'reference_types' => $referenceTypes,
  193.             'create' => true,
  194.             'is_admin' => true,
  195.             'showRedirectField' => false,
  196.         ));
  197.     }
  198.     /**
  199.      * Returns a Hoard entity as a csv file
  200.      *
  201.      * @Route("/{id}/csv", name="hoard_csv_download", requirements={
  202.      *  "id": "\d+"
  203.      * }, methods={"GET"})
  204.      */
  205.     public function csvExportAction($id) {
  206.         $em $this->getDoctrine()->getManager();
  207.         $hoard $em->getRepository('OxHoardBundle:Hoard')->find($id);
  208.         if(!$hoard) {
  209.             throw $this->createNotFoundException('Unable to find Hoard entity.');
  210.         }
  211.         $this->checkAccess($hoard'view');
  212.         $qb $em->createQueryBuilder();
  213.         $qb ->select(   'h'
  214.                         'partial type.{id, hoardType}',
  215.                         'coinCount',
  216.                         'partial countries.{id, country}',
  217.                         'partial province.{id, province}',
  218.                         'partial ancientPlace.{id, ancientPlace}',
  219.                         'partial location_detail.{id, findSpotLocationDetail}',
  220.                         'partial reign1.{id, reign}',
  221.                         'partial reign2.{id, reign}',
  222.                         'partial disc_method.{id, discoveryMethod}',
  223.                         'partial disc_landuse.{id, discoveryLandUse}',
  224.                         'partial recovery_method.{id, archaeologyRecoveryMethod}',
  225.                         'partial site_context.{id, archaeologySiteContext}',
  226.                         'partial arch_site_context_details.{id, archaeologySiteContextDetail}',
  227.                         'partial arch_period.{id, archaeologyPeriod}',
  228.                         'partial arch_end_period.{id, archaeologyPeriod}',
  229.                         'partial arch_context_natures.{id, title}',
  230.                         'partial findspot_rating.{id, rating}',
  231.                         'partial contextual_rating.{id, rating}',
  232.                         'partial rating.{id, rating}',
  233.                         'partial containers.{id, container}',
  234.                         'partial objects.{id, object}',
  235.                         'partial coinLevelData.{id, coinLevelData}',
  236.                         'partial hoardReferences.{id, reference_str}',
  237.                         'partial references.{id, abbreviation, authors, year, title}',
  238.                         'partial refType.{id}',
  239.                     )
  240.             ->from('OxHoardBundle:Hoard''h')
  241.             ->where('h.id = :hoardId')
  242.             ->setParameter('hoardId'$hoard->getId())
  243.             ->leftJoin('h.hoardType''type')
  244.             ->leftJoin('h.coinCount''coinCount')
  245.             ->leftJoin('h.countries''countries')
  246.             ->leftJoin('h.province''province')
  247.             ->leftJoin('h.ancientPlace''ancientPlace')
  248.             ->leftJoin('h.findSpotLocationDetail''location_detail')
  249.             ->leftJoin('h.closingReign1''reign1')
  250.             ->leftJoin('h.closingReign2''reign2')
  251.             ->leftJoin('h.discoveryMethod''disc_method')
  252.             ->leftJoin('h.discoveryLandUse''disc_landuse')
  253.             ->leftJoin('h.archaeologyRecoveryMethod''recovery_method')
  254.             ->leftJoin('h.archaeologySiteContext''site_context')
  255.             ->leftJoin('h.archaeologySiteContextDetails''arch_site_context_details')
  256.             ->leftJoin('h.archaeologyPeriod''arch_period')
  257.             ->leftJoin('h.archaeologyContextNatures''arch_context_natures')
  258.             ->leftJoin('h.archaeologyEndPeriod''arch_end_period')
  259.             ->leftJoin('h.findSpotRating''findspot_rating')
  260.             ->leftJoin('h.contextualRating''contextual_rating')
  261.             ->leftJoin('h.rating''rating')
  262.             ->leftJoin('h.containers''containers')
  263.             ->leftJoin('h.objects''objects')
  264.             ->leftJoin('h.coinLevelData''coinLevelData')
  265.             ->leftJoin('h.hoardReferences''hoardReferences')
  266.             ->leftJoin('hoardReferences.reference''references')
  267.             ->leftJoin('references.referenceType''refType')
  268.             ;
  269.             $data $qb->getQuery()->getArrayResult();
  270.             
  271.             // echo '<pre>'; print_r($data); echo '</pre>';
  272.             
  273.             $isAuthenticated false;
  274.             if($this->getUser()) {
  275.                 $isAuthenticated true;
  276.             }
  277.             
  278.             //loop over hoards and flag if they should be hidden
  279.             // var_dump($data);
  280.             foreach($data as &$hoard) {
  281.                 if($isAuthenticated) {
  282.                     $hoard['can_see_location'] = true;
  283.                 } else {
  284.                     $hoard['can_see_location'] = !$hoard['hideLocation'];
  285.                 }
  286.                 
  287.                 $hoardOnlineDatabases = array();
  288.                 $hoard['hoardReferences'] = array_filter($hoard['hoardReferences'], function($reference) use (&$hoardOnlineDatabases) {
  289.                     if ($reference && $reference['reference'] &&
  290.                         $reference['reference']['referenceType'] &&
  291.                         $reference['reference']['referenceType']['id'] &&
  292.                         $reference['reference']['referenceType']['id'] != '11') { // reference's type is a "Permalink in other online database"
  293.                             return true;
  294.                     } else {
  295.                         $hoardOnlineDatabases[] = $reference;
  296.                         return false;
  297.                     }
  298.                 });
  299.                 $hoard['hoardOnlineDatabases'] = $hoardOnlineDatabases;
  300.             }
  301.             return $this->outputCSV($data'hoard_'.$id);
  302.     }
  303.     /**
  304.      * Returns a Hoard entity as a csv file
  305.      *
  306.      * @Route("/{id}/csv/coins", name="hoard_csv_download_coins", requirements={
  307.      *  "id": "\d+"
  308.      * }, methods={"GET"})
  309.      */
  310.     public function csvExportActionCoins($id) {
  311.         $em $this->getDoctrine()->getManager();
  312.         $hoard $em->getRepository('OxHoardBundle:Hoard')->find($id);
  313.         if(!$hoard) {
  314.             throw $this->createNotFoundException('Unable to find Hoard entity.');
  315.         }
  316.         $this->checkAccess($hoard'view');
  317.         $qb $em->createQueryBuilder();
  318.         $qb->select(
  319.                 'partial h.{id, findSpotName, findSpotLatitude, findSpotLongitude, terminalYear1, terminalYear2},
  320.                 c,
  321.                 partial countries.{id, country},
  322.                 partial coinLevelData.{id, coinLevelData},
  323.                 partial period.{id, period},
  324.                 partial d.{id, denomination},
  325.                 partial material.{id, material},
  326.                 partial mints.{id, mint},
  327.                 partial reigns.{id, reign},
  328.                 partial persons.{id, person, title},
  329.                 partial condition.{id, condition},
  330.                 partial aspects.{id, aspect},
  331.                 partial container.{id, container},
  332.                 partial coinAdditionalFields.{id, comment},
  333.                 partial additionalFields.{id, additionalField, description},
  334.                 partial coinReferences.{id, reference_str, comment},
  335.                 partial references.{id, abbreviation, authors, year, title, sortValue, hasOwnColumn},
  336.                 partial ocre.{id, sortValue},
  337.                 partial ocre_person.{id, person},
  338.                 partial ocre_mint.{id, mint}'
  339.             )
  340.             ->from('OxHoardBundle:Hoard''h')
  341.             ->where('h.id = :hoardId')
  342.             ->leftJoin('h.countries''countries')
  343.             ->leftJoin('h.coinLevelData''coinLevelData')
  344.             ->setParameter('hoardId'$hoard->getId())
  345.             ->leftjoin('h.coins''c')
  346.             ->leftjoin('c.period''period')
  347.             ->leftjoin('c.denominations''d')
  348.             ->leftjoin('d.material''material')
  349.             ->leftjoin('c.mints''mints')
  350.             ->leftjoin('c.reigns''reigns')
  351.             ->leftjoin('c.persons''persons')
  352.             ->leftjoin('c.condition''condition')
  353.             ->leftjoin('c.aspects''aspects')
  354.             ->leftjoin('c.container''container')
  355.             ->leftJoin('c.coinAdditionalFields''coinAdditionalFields')
  356.             ->leftJoin('coinAdditionalFields.additionalField''additionalFields')
  357.             ->leftJoin('c.coinReferences''coinReferences')
  358.             ->leftJoin('coinReferences.reference''references')
  359.             ->leftJoin('reigns.ocreLookups''ocre')
  360.             ->leftJoin('ocre.person''ocre_person')
  361.             ->leftJoin('ocre.mint''ocre_mint')
  362.             ;
  363.         $data $qb->getQuery()->getArrayResult();    
  364.         $refData $this->processHoardDataForCSV($data);
  365.         //for some reason the results are wrapped in an array here, unlike when exporting from search results.
  366.         return $this->outputCSV(array($data[0]), 'hoard_'.$id.'_coins'true$refData);
  367.     }
  368.     //process the hoard data
  369.     // This sorts the coins and normalises the references to consistent columns 
  370.     private function processHoardDataForCSV(&$data) {
  371.         $seenOwnColumnReferences = [];
  372.         $seenOtherReferences = [];
  373.     
  374.         //sort the references by sort value
  375.         foreach($data as &$hoard) {
  376.             foreach($hoard['coins'] as &$coin) {
  377.                 //get the sort value
  378.                 $reigns $coin['reigns'];
  379.                 if($reigns && count($reigns)) {
  380.                     //just look at first reign
  381.                     $reign $reigns[0];
  382.                     $lookups $reign['ocreLookups'];
  383.                     foreach($lookups as $lookup) {
  384.                         $coinPersons = [];
  385.                         foreach($coin['persons'] as $person) {
  386.                             $coinPersons[] = $person['id'];
  387.                         }
  388.                         if(in_array($lookup['person']['id'], $coinPersons)) {
  389.                             //check mint if necessary
  390.                             if(isset($lookup['mint'])) {
  391.                                 //see if it matches
  392.                                 $coinMints = [];
  393.                                 foreach($coin['mints'] as $mint) {
  394.                                     $coinMints[] = $mint['id'];
  395.                                 }
  396.                                 if(in_array($lookup['mint']['id'], $coinMints)) {
  397.                                     //this is a match
  398.                                     $coin['sortValue'] = $lookup['sortValue'];
  399.                                     // echo 'found a match with mint, sort value = '.$coin['sortValue'].'<br/>';
  400.                                 }
  401.                             } else {
  402.                                 //this is a match
  403.                                 $coin['sortValue'] = $lookup['sortValue'];
  404.                                 // echo 'found a match without mint, sort value = '.$coin['sortValue'].'<br/>';
  405.                             }
  406.                         }
  407.                     }
  408.                 }
  409.                 // echo '<pre>'; print_r($coin); echo '</pre>';
  410.                 
  411.                 //note which references are seen
  412.                 // keep separate arrays of references which should have their own column
  413.                 foreach($coin['coinReferences'] as $coinRef) {
  414.                     $ref $coinRef['reference'];
  415.                     if($ref) {
  416.                         if($coinRef['reference']['hasOwnColumn']) { 
  417.                             if(!in_array($ref$seenOwnColumnReferences)) {
  418.                                 $seenOwnColumnReferences[] = $ref;
  419.                             }
  420.                         } else {
  421.                             if(!in_array($ref$seenOtherReferences)) {
  422.                                 $seenOtherReferences[] = $ref;
  423.                             }
  424.                         }
  425.                     }
  426.                 }
  427.                 
  428.                 usort($coin['coinReferences'], array($this,"compareRefs"));
  429.             }
  430.             
  431.             
  432.             //now sort coins by their sort value
  433.             usort($seenOwnColumnReferences, array($this,"compareSeenRefs"));
  434.             usort($hoard['coins'], array($this,"compareCoins"));
  435.             
  436.             // var_dump($hoard);
  437.         }
  438.         //at this point we have a list of coin references seen in this dataset, and the coin references are sorted
  439.         
  440.         //rewrite the coin references with the references in the relevant columns
  441.         $maxOtherReferences 0;
  442.         foreach($data as &$hoard) {
  443.             foreach($hoard['coins'] as &$coin) {
  444.                 //keyed array of those references which should have their own column
  445.                 $newOwnColumnCoinReferences = [];
  446.                 
  447.                 //plain array of all other references
  448.                 $newOtherCoinReferences = [];
  449.                 
  450.                 $coinReferences $coin['coinReferences'];
  451.                 foreach($coinReferences as $coinRef) {
  452.                     if($coinRef['reference']['hasOwnColumn']) {
  453.                         $key $coinRef['reference']['id'];
  454.                         $newOwnColumnCoinReferences[$key] = $coinRef;
  455.                     } else {
  456.                         $newOtherCoinReferences[] = $coinRef;
  457.                     }
  458.                 }
  459.                 
  460.                 
  461.                 
  462.                 //now build the full array of references
  463.                 $newCoinReferences = [];
  464.                 
  465.                 // var_dump($seenOwnColumnReferences);
  466.                 foreach($seenOwnColumnReferences as $ownColumnRef) {
  467.                     $val '';
  468.                     // var_dump($seenOwnColumnReferences);
  469.                     if(isset($newOwnColumnCoinReferences[$ownColumnRef['id']])) {
  470.                         
  471.                         $val $newOwnColumnCoinReferences[$ownColumnRef['id']];
  472.                     } else {
  473.                         $val = array();
  474.                     }
  475.                     $newCoinReferences[] = $val;
  476.                 }
  477.                 
  478.                 //keep track of how many columns we need
  479.                 if(count($newOtherCoinReferences) > $maxOtherReferences) {
  480.                     $maxOtherReferences count($newOtherCoinReferences);
  481.                 }
  482.                 
  483.                 
  484.                 //add the non-own-column references
  485.                 $newCoinReferences array_merge($newCoinReferences$newOtherCoinReferences);
  486.                 $coin['coinReferences'] = $newCoinReferences;
  487.             }
  488.         }
  489.         
  490.         //return some data about the references seen
  491.         return array(
  492.             'own_column_references' => $seenOwnColumnReferences,
  493.             'num_other_references' => $maxOtherReferences
  494.         );
  495.     }
  496.     function compareCoins($a$b) {
  497.         //compare period
  498.         if (isset($a['period'])) { $periodA $a['period']['id']; } else { $periodA 0; }
  499.         if (isset($b['period'])) { $periodB $b['period']['id']; } else { $periodB 0; }
  500.         if($periodA $periodB) { return -1; }
  501.         else if($periodB $periodA ) { return 1; }
  502.         else {
  503.             if(isset($a['sortValue'])) { $sortA $a['sortValue']; } else { $sortA 0; }
  504.             if(isset($b['sortValue'])) { $sortB $b['sortValue']; } else { $sortB 0; }
  505.             //periods are equal, compare by ocre table
  506.             if($sortA $sortB) { return 1; }
  507.             else if($sortB $sortA) { return -1; }
  508.             else {
  509.                 //same ocre prefix
  510.                 //todo compare ric reference value
  511.                 $refValueA $this->getSortableRef($a);
  512.                 if($refValueA) {
  513.                     $refValueB $this->getSortableRef($b);
  514.                     if($refValueB) {
  515.                         //compare numerical part
  516.                         $numA intval($refValueA['num']);
  517.                         $numB intval($refValueB['num']);
  518.                         if($numA $numB) { return 1; }
  519.                         else if($numB $numA) {return -1; }
  520.                         else {
  521.                             //compare alphabetic part
  522.                             $lowerA strtolower($refValueA['char']);
  523.                             $lowerB strtolower($refValueB['char']);
  524.                             if($lowerA $lowerB) { return -1; }
  525.                             else if($lowerB $lowerA) { return 1; }
  526.                             else return 0;
  527.                         }
  528.                     }
  529.                 }
  530.                 
  531.                 return 0;
  532.             }
  533.         }
  534.     } 
  535.     //given an array of coinData, get the most relevant reference as an array of numerical part and alphabetic part
  536.     function getSortableRef($coinArray) {
  537.         // var_dump($coinArray);
  538.         foreach($coinArray['coinReferences'] as $coinRef) {
  539.             if(isset($coinRef['reference'])) {
  540.                 $refs = ['RIC''RIC (2nd ed.)''RRC''RPC'];
  541.                 if(in_array($coinRef['reference']['abbreviation'], $refs)) {
  542.                     //this is a reference we care about sorting on
  543.                     //extract the numerical and alphabetic components
  544.                     $matches null;
  545.                     if (preg_match('/(\d+)\/(\d+)(\w*)/'$coinRef['reference_str'], $matches)) {
  546.                         //RRC reference format e.g. 123/1b
  547.                         //derive a number that can be used to compare
  548.                         $num $matches[1] * 1000 $matches[2];
  549.                         $refData = array(
  550.                             'num' => $num,
  551.                             'char' => $matches[3]
  552.                         );
  553.                         return $refData;
  554.                     } else if (preg_match('/(\d+)(\w*)/'$coinRef['reference_str'], $matches)) {
  555.                         //RIC reference format e.g. 123a (or somethings 123a/b or )
  556.                         $refData = array(
  557.                             'num' => $matches[1],
  558.                             'char' => $matches[2]
  559.                         );
  560.                         return $refData;
  561.                     }
  562.                 }
  563.             }
  564.         }
  565.         return null;
  566.     }
  567.     //order coinreference array data by sortvalue of the reference (decreasing)
  568.     function compareSeenRefs($a$b) {
  569.         if($a['sortValue'] > $b['sortValue']) {
  570.             return -1;
  571.         } else if ($a['sortValue'] == $b['sortValue']) {
  572.             return 0;
  573.         } else {
  574.             return 1;
  575.         }
  576.     }
  577.     //order coinreference array data by sortvalue of the reference (decreasing)
  578.     function compareRefs($a$b) {
  579.         if($a['reference']['sortValue'] > $b['reference']['sortValue']) {
  580.             return -1;
  581.         } else if ($a['reference']['sortValue'] == $b['reference']['sortValue']) {
  582.             return 0;
  583.         } else {
  584.             return 1;
  585.         }
  586.     }
  587.     /**
  588.      * Finds and displays a Hoard entity.
  589.      *
  590.      * @Route("/{id}", name="hoard_show", requirements={
  591.      *    "id": "\d+"
  592.      * }, methods={"GET"})
  593.      * @Template()
  594.      */
  595.     public function showAction($id)
  596.     {
  597.         $isAdmin $this->userIsAdmin();
  598.         $em $this->getDoctrine()->getManager();
  599.         $hoard $em->getRepository('OxHoardBundle:Hoard')->find($id);
  600.         // if the hoard is not found check if it soft-deleted
  601.         if (!$hoard) {
  602.             $em->getFilters()->disable('softdeleteable');
  603.             $hoard $em->getRepository('OxHoardBundle:Hoard')->find($id);
  604.             $em->getFilters()->enable('softdeleteable');
  605.             // if it is not soft-deleted return "not found"
  606.             if (!$hoard) {
  607.                 throw $this->createNotFoundException('Unable to find Hoard entity.');
  608.             } else {
  609.                 // else check if it is really soft-deleted and redirect to the redirectId
  610.                 $redirect_id $hoard->getRedirectToHoard();
  611.                 if ($hoard->getDeletedAt() && $redirect_id) {
  612.                     return $this->redirect($this->generateUrl('hoard_show', array('id' => $redirect_id)));
  613.                 } else {
  614.                     throw $this->createNotFoundException('Unable to find Hoard entity.');
  615.                 }
  616.             }
  617.         }
  618.         // validate permission
  619.         $this->checkAccess ($hoard'view');
  620.         $deleteForm $this->createDeleteForm($id);
  621.         $images =$this->getImages($hoard);
  622.         $discoveryMonth1Text $this->monthTextForMonth($hoard->getDiscoverymonth1());
  623.         $discoveryMonth2Text $this->monthTextForMonth($hoard->getDiscoverymonth2());
  624.         foreach($images as &$image) {
  625.             //add metadata about the image
  626.             $hoardimage $em->getRepository('OxHoardBundle:HoardImage')->find($image['hoardImages_id']);
  627.             $image['uri1'] = $hoardimage->getUri1();
  628.             $image['uri2'] = $hoardimage->getUri2();
  629.             $image['comment'] = $hoardimage->getComment();
  630.         }
  631.         $isAuthenticated false;
  632.         if($this->getUser()) { $isAuthenticated true; }
  633.         if (!$isAuthenticated && !$hoard->getCoinDataValidatedByUser()) {
  634.             $show_coins false;
  635.             $show_coins_summary false;
  636.         } else {
  637.             $show_coins $this->security->isGranted('view_coins'$hoard);
  638.             $show_coins_summary $this->security->isGranted('view_coins_summary'$hoard);
  639.         }
  640.         
  641.         $hoardReferences $hoard->getHoardReferences();
  642.         $iterator $hoardReferences->getIterator();
  643.         $iterator->uasort(function ($a$b) {
  644.             if ($a->getReference() && $b->getReference()) {
  645.                 if ($a->getReference()->getYear() != $b->getReference()->getYear()) {
  646.                     // sort by reference year first
  647.                     return $a->getReference()->getYear() - $b->getReference()->getYear();
  648.                 } else {
  649.                     // alphabetically by authors if years are the same
  650.                     return strcasecmp($a->getReference()->getAuthors(), $b->getReference()->getAuthors());
  651.                 }
  652.             }
  653.         });
  654.         $hoardReferences->clear();
  655.         foreach($iterator as $item) {
  656.             $hoardReferences->add($item);
  657.         }
  658.         // Create separate arrays for OnlineDB references and other references.
  659.         $hoardReferenceArray = [];
  660.         $onlineDatabaseReferenceArray = [];
  661.         // Loop through HoardReferences.
  662.         foreach ($hoardReferences->getValues() as $reference) {
  663.             if ($referenceType $reference->getReference() && $reference->getReference()->getReferenceType()) {
  664.                 // Check ID, if matches Online Database, add to relevant array.
  665.                 $referenceType $reference->getReference()->getReferenceType()->getId();
  666.                 if ($referenceType === 11) {
  667.                     $onlineDatabaseReferenceArray[] = $reference;
  668.                 }
  669.                 else {
  670.                     $hoardReferenceArray[] = $reference;
  671.                 }
  672.             }
  673.         }
  674.         // Generate a permalink to display on the hoard page.
  675.         $permalink "https://" $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
  676.         
  677.         $reigns $em->getRepository('OxHoardBundle:Reign')->findAll();
  678.         $persons $em->getRepository('OxHoardBundle:Person')->findAll();
  679.         return array(
  680.             'images'     => $images,
  681.             'hoard'      => $hoard,
  682.             'hoardReferences' => $hoardReferenceArray,
  683.             'onlineDatabaseReferences' => $onlineDatabaseReferenceArray,
  684.             'is_admin'  => $isAdmin,
  685.             'is_authenticated'  => $isAuthenticated,
  686.             'can_see_location'   => $isAuthenticated || !$hoard->getHideLocation(),
  687.             'is_authorised_to_edit' => $this->checkAccess($hoard'edit'false),
  688.             'show_coins' => $show_coins,
  689.             'show_coins_summary' => $show_coins_summary,
  690.             'discoverymonth1_text' => $discoveryMonth1Text,
  691.             'discoverymonth2_text' => $discoveryMonth2Text,
  692.             'permalink' => $permalink,
  693.             'reigns' => $reigns,
  694.             'persons' => $persons
  695.         );
  696.     }
  697.     private function monthTextForMonth($num) {
  698.         switch($num) {
  699.             case 1:
  700.                 return 'Jan';
  701.             case 2:
  702.                 return 'Feb';
  703.             case 3:
  704.                 return 'Mar';
  705.             case 4:
  706.                 return 'Apr';
  707.             case 5:
  708.                 return 'May';
  709.             case 6:
  710.                 return 'Jun';
  711.             case 7:
  712.                 return 'Jul';
  713.             case 8:
  714.                 return 'Aug';
  715.             case 9:
  716.                 return 'Sep';
  717.             case 10:
  718.                 return 'Oct';
  719.             case 11:
  720.                 return 'Nov';
  721.             case 12:
  722.                 return 'Dec';
  723.             default:
  724.                 return '';
  725.         }
  726.     }
  727.     /**
  728.      * @Route("/coinData/{id}", name="ajax_hoard_coin_data", requirements={
  729.      *      "id": "\d+"
  730.      * }, methods={"GET"})
  731.      */
  732.     public function ajaxHoardCoins($id)
  733.     {
  734.         $em $this->getDoctrine()->getManager();
  735.         $hoard$em->getRepository('OxHoardBundle:Hoard')->find($id);
  736.         if(!$hoard) {
  737.             throw $this->createNotFoundException('Unable to find Hoard entity.');
  738.         }
  739.         //check that the user can at least see the coins summary
  740.         $isAuthenticated false;
  741.         if($this->getUser()) { $isAuthenticated true; }
  742.         if (!$isAuthenticated && !$hoard->getCoinDataValidatedByUser()) {
  743.             $show_coins false;
  744.         } else {
  745.             $show_coins $this->security->isGranted('view_coins_summary'$hoard);;
  746.         }
  747.         if ($show_coins) {
  748.             $coinData $this->getCoinData($hoard);
  749.             return new JsonResponse($coinData);
  750.         } else {
  751.             throw new AccessDeniedException('Unauthorised access!');
  752.         }
  753.     }
  754.     private function getCoinData($hoard) {
  755.         $em $this->getDoctrine()->getManager();
  756.         // Generate the coin summaries
  757.         $queryBuilder $em->createQueryBuilder();
  758.         $queryBuilder->select('c, aspects, period, reigns, mints, persons, denominations, materials, partial coin_references.{id, reference_str}, partial ref.{id, abbreviation}')
  759.             ->from('OxHoardBundle:Coin''c')
  760.             ->leftJoin('c.reigns''reigns')
  761.             ->leftJoin('c.persons''persons')
  762.             ->leftJoin('c.denominations''denominations')
  763.             ->leftJoin('denominations.material''materials')
  764.             ->leftJoin('c.mints''mints')
  765.             ->leftJoin('c.period''period')
  766.             ->leftJoin('c.aspects''aspects')
  767.             ->leftJoin('c.coinReferences''coin_references')
  768.             ->leftJoin('coin_references.reference''ref')
  769.             ;
  770.         $queryBuilder->where('c.hoard = :hoard')
  771.             ->setParameter('hoard'$hoard);
  772.         $query $queryBuilder->getQuery();
  773.         $queryResult $query->getArrayResult();
  774.         return $queryResult;
  775.     }
  776.     /**
  777.      * Displays a form to edit an existing Hoard entity.
  778.      *
  779.      * @Route("/{id}/edit", name="hoard_edit", methods={"GET"})
  780.      * @Template()
  781.      */
  782.     public function editAction($id)
  783.     {
  784.         $em $this->getDoctrine()->getManager();
  785.         $em->getFilters()->enable('softdeleteable');
  786.         $hoard $em->getRepository('OxHoardBundle:Hoard')->find($id);
  787.         $showRedirectField false;
  788.         if (!$hoard) {
  789.             $em->getFilters()->disable('softdeleteable');
  790.             $hoard $em->getRepository('OxHoardBundle:Hoard')->find($id);
  791.             $em->getFilters()->enable('softdeleteable');
  792.             // if it is not soft-deleted return "not found"
  793.             if (!$hoard) {
  794.                 throw $this->createNotFoundException('Unable to find Hoard entity.');
  795.             } else {
  796.                 // else check if it is really soft-deleted to enable the redirect id field
  797.                 if ($hoard->getDeletedAt() && $this->userIsAdmin()) {
  798.                     $showRedirectField true;
  799.                 } else {
  800.                     throw $this->createNotFoundException('Unable to find Hoard entity.');
  801.                 }
  802.             }
  803.         }
  804.         // validate permission
  805.         $this->checkAccess($hoard'edit');
  806.         $editForm $this->createEditForm($hoard);
  807.         $deleteForm $this->createDeleteForm($id);
  808.         $objects $hoard->getObjects();
  809.         $object_prototype = array(
  810.             'id' => '__id__',
  811.             'object' => '',
  812.             'description' => '',
  813.         );
  814.         $container_prototype = array(
  815.             'id' => '__id__',
  816.             'container' => '',
  817.             'comment' => ''
  818.         );
  819.         // echo '<pre>'; print_r($object_prototype); exit;
  820.         //get the list of image
  821.         $images $this->getImages($hoard);
  822.         $coinAddForm $this->createForm(SummaryCoinType::class, null, array());
  823.         //reference types to pass to the view
  824.         $referenceTypes $em->createQuery('SELECT rt FROM OxHoardBundle:ReferenceType rt ORDER BY rt.sortValue DESC, rt.referenceType ASC')->getResult();
  825.         $massEditCoinsData $this->massEditCoinsData();
  826.         $disaggregateForm $this->createDisaggregateForm($id);
  827.         return array(
  828.             'object_proto' => $object_prototype,
  829.             'container_proto' => $container_prototype,
  830.             'hoard'      => $hoard,
  831.             'images' => $images,
  832.             'coin_add_form' => $coinAddForm->createView(),
  833.             'edit_form'   => $editForm->createView(),
  834.             'delete_form' => $deleteForm->createView(),
  835.             'reference_types' => $referenceTypes,
  836.             'create' => false,
  837.             'massEditCoinsData' => $massEditCoinsData,
  838.             'disaggregate_form' => $disaggregateForm->createView(),
  839.             'is_admin' => $this->userIsAdmin(),
  840.             'showRedirectField' => $showRedirectField,
  841.         );
  842.     }
  843.     /**
  844.      * Shows the revisions of an existing Hoard entity.
  845.      *
  846.      * @Route("/{id}/revisions", name="hoard_revisions", methods={"GET"})
  847.      * @Template("@OxHoardBundle/hoard/revisions.html.twig")
  848.      */
  849.     public function revisionsAction(Request $request$id) {
  850.         // check User
  851.         $em $this->getDoctrine()->getManager();
  852.         $hoard $em->getRepository('OxHoardBundle:Hoard')->find($id);
  853.         $this->checkAccess($hoard'edit');
  854.         $auditConfig = new AuditConfiguration();
  855.         $auditConfig->setAuditedEntityClasses([Hoard::class]);
  856.         $auditManager = new AuditManager($auditConfig);
  857.         $auditReader $auditManager->createAuditReader($em);
  858.         $revisions $auditReader->findRevisions(Hoard::class, $id);
  859.       
  860.         $revs = [];
  861.         foreach($revisions as $key => $revision) {
  862.             $revs[$key]['username'] = $revision->getUsername();
  863.             $revs[$key]['rev'] = $revision->getRev();
  864.             $revs[$key]['date'] = $revision->getTimestamp()->format("H:i:s d-m-Y");
  865.         }
  866.       
  867.         $coinsRevs = [];
  868.         $coins $hoard->getCoins();
  869.         foreach($coins as $coin) {
  870.                 $coinId $coin->getId();
  871.                 $auditConfig = new AuditConfiguration();
  872.                 $auditConfig->setAuditedEntityClasses([Coin::class]);
  873.                 $auditManager = new AuditManager($auditConfig);
  874.                 $auditReader $auditManager->createAuditReader($em);
  875.                 $coinRevisions $auditReader->findRevisions(Coin::class, $coinId);
  876.                 foreach($coinRevisions as $key => $revision) {
  877.                     $coinsRevs[$coinId][$key]['username'] = $revision->getUsername();
  878.                     $coinsRevs[$coinId][$key]['rev'] = $revision->getRev();
  879.                     $coinsRevs[$coinId][$key]['date'] = $revision->getTimestamp()->format("H:i:s d-m-Y");
  880.                 }
  881.         }
  882.         return array(
  883.             'revs' => $revs,
  884.             'coinsRevs' => $coinsRevs,
  885.             'hoard'      => $hoard,
  886.         );
  887.     }
  888.     
  889.     private function massEditCoinsData() {
  890.         $em $this->getDoctrine()->getManager();
  891.         
  892.         //get all available options for the various dropdowns
  893.         $data = array();
  894.         $data['persons'] = $em->getRepository('OxHoardBundle:Person')->findAll();
  895.         $data['period'] = $em->getRepository('OxHoardBundle:Period')->findAll();
  896.         $data['reigns'] = $em->getRepository('OxHoardBundle:Reign')->findAll();
  897.         $data['mints'] = $em->getRepository('OxHoardBundle:Mint')->findAll();
  898.         $data['denominations'] = $em->getRepository('OxHoardBundle:Denomination')->findAll();
  899.         $data['condition'] = $em->getRepository('OxHoardBundle:Condition')->findAll();
  900.         $data['aspects'] = $em->getRepository('OxHoardBundle:Aspect')->findAll();
  901.         $data['references'] = $em->getRepository('OxHoardBundle:Reference')->findAll();
  902.         return $data;
  903.     }
  904.     /****
  905.      * Get a list of image file names/ids for the given hoard entity
  906.      */
  907.     private function getImages(Hoard $entity) {
  908.         $hoardImages $entity->getHoardImages();
  909.         $images = array();
  910.         foreach($hoardImages as $hoardImage) {
  911.             $imageSrc null;
  912.             $image $hoardImage->getImage();
  913.             if(!empty($image)) {
  914.                 $imageSrc 'media/'.$image->getFilename();
  915.             }
  916.             array_push($images, array(
  917.                'src' => $imageSrc,
  918.                'hoardImages_id' => $hoardImage->getId()
  919.             ));
  920.         }
  921.         return $images;
  922.     }
  923.     /**
  924.     * Creates a form to edit a Hoard entity.
  925.     *
  926.     * @param Hoard $entity The entity
  927.     *
  928.     * @return \Symfony\Component\Form\Form The form
  929.     */
  930.     private function createEditForm(Hoard $entity)
  931.     {
  932.         $formOptions = array(
  933.             'action' => $this->generateUrl('hoard_update', array('id' => $entity->getId())),
  934.             'method' => 'PUT',
  935.             'em' => $this->getDoctrine()->getManager(),
  936.         );
  937.         //pass in the list of allowed countries
  938.         if(!$this->userIsAdmin()) {
  939.             $formOptions['countries'] = $this->getUser()->getAccessibleCountries();
  940.         }
  941.         $form $this->createForm(HoardType::class, $entity$formOptions);
  942.         if($this->userIsAdmin())
  943.         {
  944.             $form->add('validatedByAdmin');
  945.         }
  946.         $form->add('submit'SubmitType::class, array('label' => 'Update'));
  947.         return $form;
  948.     }
  949.     /**
  950.      * Edits an existing Hoard entity.
  951.      *
  952.      * @Route("/{id}", name="hoard_update", methods={"PUT"})
  953.      * @Template("@OxHoardBundle/hoard/edit.html.twig")
  954.      */
  955.     public function updateAction(Request $request$id)
  956.     {
  957.         $em $this->getDoctrine()->getManager();
  958.         $em->getFilters()->enable('softdeleteable');
  959.         $hoard $em->getRepository('OxHoardBundle:Hoard')->find($id);
  960.         if (!$hoard) {
  961.             $em->getFilters()->disable('softdeleteable');
  962.             $hoard $em->getRepository('OxHoardBundle:Hoard')->find($id);
  963.             $em->getFilters()->enable('softdeleteable');
  964.             // if it is not soft-deleted or user is not admin return "not found"
  965.             if (!$hoard || !$this->userIsAdmin()) {
  966.                 throw $this->createNotFoundException('Unable to find Hoard entity.');
  967.             }
  968.         }
  969.         // validate permission
  970.         $this->checkAccess($hoard'edit');
  971.         $deleteForm $this->createDeleteForm($id);
  972.         $editForm $this->createEditForm($hoard);
  973.         $editForm->handleRequest($request);
  974.         $now = new \DateTime('now');
  975.         if ($editForm->isValid()) {
  976.             //images
  977.             $hoardImages $hoard->getHoardImages();
  978.             foreach($hoardImages as $hoardImage)
  979.             {
  980.                 $em->persist($hoardImage);
  981.                 if($hoardImage->getDeleted())
  982.                 {
  983.                     $em->remove($hoardImage);
  984.                 }
  985.             }
  986.             //persist or delete references
  987.             $hoardReferences $hoard->getHoardReferences();
  988.             foreach($hoardReferences as $reference)
  989.             {
  990.                 echo 'reference found <br>';
  991.                 if($reference->getDeleted())
  992.                 {
  993.                     //do soft delete - also persist deleted flag
  994.                     $em->persist($reference);
  995.                     //clear this reference from the hoard
  996.                     $reference->setHoard(null);
  997.                     //need to flush before removing
  998.                     $em->flush();
  999.                     $em->remove($reference);
  1000.                 }
  1001.                 else
  1002.                 {
  1003.                     $em->persist($reference);
  1004.                     $reference->setHoard($hoard);
  1005.                 }
  1006.             }
  1007.             //mark as unvalidated since it has changed
  1008.             if(!$this->userIsAdmin())
  1009.             {
  1010.                 $hoard->markUnvalidatedByAdmin();
  1011.             }
  1012.             
  1013.             $hoard->setModified($this->getUser());
  1014.             $this->addRelatedCountries($hoard);
  1015.             $em->flush();
  1016.             $request->getSession()
  1017.                 ->getFlashBag()
  1018.                 ->add('success''Hoard has been updated');
  1019.             return $this->redirect($this->generateUrl('hoard_show', array('id' => $id)));
  1020.         }
  1021.         //get the list of image
  1022.         $images $this->getImages($hoard);
  1023.         $object_prototype = array(
  1024.             'id' => '__id__',
  1025.             'object' => '',
  1026.             'description' => '',
  1027.         );
  1028.         $container_prototype = array(
  1029.             'id' => '__id__',
  1030.             'container' => '',
  1031.             'comment' => ''
  1032.         );
  1033.         $referenceTypes $em->createQuery('SELECT rt FROM OxHoardBundle:ReferenceType rt ORDER BY rt.sortValue DESC, rt.referenceType ASC')->getResult();
  1034.         $request->getSession()
  1035.             ->getFlashBag()
  1036.             ->add('error''Error updating hoard!');
  1037.         return array(
  1038.             'object_proto' => $object_prototype,
  1039.             'container_proto' => $container_prototype,
  1040.             'hoard'      => $hoard,
  1041.             'images'      => $images,
  1042.             'edit_form'   => $editForm->createView(),
  1043.             'delete_form' => $deleteForm->createView(),
  1044.             'reference_types' => $referenceTypes,
  1045.             'create' => false,
  1046.         );
  1047.     }
  1048.     /**
  1049.      * Deletes a Hoard entity.
  1050.      *
  1051.      * @Route("/{id}", name="hoard_delete", methods={"DELETE"})
  1052.      */
  1053.     public function deleteAction(Request $request$id)
  1054.     {
  1055.         $form $this->createDeleteForm($id);
  1056.         $form->handleRequest($request);
  1057.         if ($form->isValid()) {
  1058.             $em $this->getDoctrine()->getManager();
  1059.             $entity $em->getRepository('OxHoardBundle:Hoard')->find($id);
  1060.             if (!$this->getUser() || !($this->getUser()->hasRole('ROLE_ADMIN') || $this->getUser()->hasRole('ROLE_SUPER_ADMIN'))) {
  1061.                 $request->getSession()->getFlashBag()
  1062.                     ->add('error''Unable to delete Hoard. Only admins can delete hoards.');
  1063.                 return $this->redirect($this->generateUrl('hoard_edit', array('id' => $entity->getId())));
  1064.             }
  1065.             if (!$entity) {
  1066.                 throw $this->createNotFoundException('Unable to find Hoard entity.');
  1067.             }
  1068.             // validate permission
  1069.             $this->checkAccess($entity'delete');
  1070.             $em->remove($entity);
  1071.             $em->flush();
  1072.         }
  1073.         return $this->redirect($this->generateUrl('hoard'));
  1074.     }
  1075.     /**
  1076.      * Creates a form to delete a Hoard entity by id.
  1077.      *
  1078.      * @param mixed $id The entity id
  1079.      *
  1080.      * @return \Symfony\Component\Form\Form The form
  1081.      */
  1082.     private function createDeleteForm($id)
  1083.     {
  1084.         return $this->createFormBuilder()
  1085.             ->setAction($this->generateUrl('hoard_delete', array('id' => $id)))
  1086.             ->setMethod('DELETE')
  1087.             ->add('submit'ButtonType::class, array(
  1088.                 'label' => 'Delete this hoard',
  1089.                 'attr' => array(
  1090.                     'class' => 'delete-button btn btn-danger'
  1091.                 )
  1092.             ))
  1093.             ->getForm()
  1094.         ;
  1095.     }
  1096.     /**
  1097.      * Add a new object to the hoard
  1098.      *
  1099.      * @Route("/{id}/ajax_add_object", name="hoard_ajax_add_object", methods={"POST"})
  1100.      */
  1101.      public function ajaxAddObject(Request $request$id)
  1102.      {
  1103.          $em $this->getDoctrine()->getManager();
  1104.          $hoard $em->getRepository('OxHoardBundle:Hoard')->find($id);
  1105.          $this->checkAccess($hoard'edit');
  1106.          $object = new HObject();
  1107.          $object->setHoard($hoard);
  1108.          $object->setCreationDate( new \DateTime("now"));
  1109.          $em->persist($object);
  1110.           //mark as unvalidated since it has changed
  1111.          if(!$this->userIsAdmin())
  1112.          {
  1113.            $hoard->markUnvalidatedByAdmin();
  1114.          }
  1115.          $em->flush();
  1116.          return new JsonResponse(
  1117.              array(
  1118.                  'id'=>$object->getId(),
  1119.                  'title'=>$object->__toString(),
  1120.                  'description'=>$object->GetDescription(),
  1121.                  'deleteURL'=>$this->generateUrl('hoard_ajax_delete_object',
  1122.                      array(
  1123.                          'id' => $hoard->getId(),
  1124.                          'object_id' => $object->getId(),
  1125.                      )
  1126.                  )
  1127.              )
  1128.          );
  1129.      }
  1130.     /**
  1131.      * Add a new coin to the hoard
  1132.      *
  1133.      * @Route("/{id}/ajax_add_coin", name="hoard_ajax_add_coin", methods={"POST"})
  1134.      */
  1135.     public function ajaxAddCoin(Request $request$id)
  1136.     {
  1137.         $em $this->getDoctrine()->getManager();
  1138.         $hoard $em->getRepository('OxHoardBundle:Hoard')->find($id);
  1139.         $this->checkAccess($hoard'edit');
  1140.         $coin = new Coin();
  1141.         $coin->setHoard($hoard);
  1142.         //get period
  1143.         $periodID $request->request->get('period');
  1144.         $period $em->getRepository('OxHoardBundle:Period')->find($periodID);
  1145.         $coin->setPeriod($period);
  1146.         $personsData $request->request->get('persons');
  1147.         if($personsData) {
  1148.             foreach ($personsData as $personID) {
  1149.                 $person $em->getRepository('OxHoardBundle:Person')->find($personID);
  1150.                 $coin->addPerson($person);
  1151.             }
  1152.         }
  1153.         $reignsData $request->request->get('reigns');
  1154.         if($reignsData) {
  1155.             foreach ($reignsData as $reignID) {
  1156.                 $reign $em->getRepository('OxHoardBundle:Reign')->find($reignID);
  1157.                 $coin->addReign($reign);
  1158.             }
  1159.         }
  1160.         $denominationsData $request->request->get('denominations');
  1161.         if($denominationsData) {
  1162.             foreach ($denominationsData as $denominationID) {
  1163.                 $denomination $em->getRepository('OxHoardBundle:Denomination')->find($denominationID);
  1164.                 $coin->addDenomination($denomination);
  1165.             }
  1166.         }
  1167.         $mintsData $request->request->get('mints');
  1168.         if($mintsData) {
  1169.             foreach($mintsData as $mintID) {
  1170.                 $mint $em->getRepository('OxHoardBundle:Mint')->find($mintID);
  1171.                 $coin->addMint($mint);
  1172.             }
  1173.         }
  1174.         $coin->setQuantity($request->request->get('quantity'));
  1175.         $coin->setCreated($this->getUser());
  1176.         $coin->setModified($this->getUser());
  1177.         $em->persist($coin);
  1178.         $em->flush();
  1179.         //prepare the response to the client, which must contain json data in the format required by the
  1180.         // backbone collection (various parameters for both display and sorting)
  1181.         $coinPeriod '';
  1182.         if($coin->getPeriod()) {
  1183.             $coinPeriod = array(
  1184.                 'period' => $coin->getPeriod()->__toString(),
  1185.                 'id' => $coin->getPeriod()->getId()
  1186.             );
  1187.         }
  1188.         $coinPersons = array();
  1189.         foreach($coin->getPersons() as $person) {
  1190.             $coinPersons[] = array ( 'person' => $person->__toString() );
  1191.         }
  1192.         $coinReigns = array();
  1193.         foreach($coin->getReigns() as $reign) {
  1194.             $coinReigns[] = array(
  1195.                 'reign' => $reign->__toString(),
  1196.                 'startDate' => $reign->getStartDate(),
  1197.                 'endDate' => $reign->getEndDate()
  1198.             );
  1199.         }
  1200.         $coinDenominations = array();
  1201.         foreach($coin->getDenominations() as $denomination) {
  1202.             $coinDenominations[] = array(
  1203.                 'denomination' => $denomination->__toString()
  1204.             );
  1205.         }
  1206.         $coinMints = array();
  1207.         foreach($coin->getMints() as $mint) {
  1208.             $coinMints[] = array(
  1209.                 'mint' => $mint->__toString(),
  1210.                 'longitude' => $mint->getLongitude()
  1211.             );
  1212.         }
  1213.         return new JsonResponse(
  1214.             array(
  1215.                 'id'=>$coin->getId(),
  1216.                 'period'=>$coinPeriod,
  1217.                 'persons'=>$coinPersons,
  1218.                 'reigns'=>$coinReigns,
  1219.                 'denominations'=>$coinDenominations,
  1220.                 'mints'=>$coinMints,
  1221.                 'quantity'=>$coin->getQuantity()
  1222.             )
  1223.         );
  1224.     }
  1225.     /**
  1226.      * checks permission of user's current request
  1227.      *
  1228.      * @param mixed $entity The entity being validated
  1229.      *
  1230.      * @param string $attribute - 'view' or 'edit' or 'delete'
  1231.      *
  1232.      * @param boolean $throwException - whether to throw an exception if false - defaults to true
  1233.      *
  1234.      * @return boolean
  1235.      *
  1236.      * @throws \Symfony\Component\Security\Core\Exception\AccessDeniedException
  1237.      */
  1238.     private function checkAccess($entity$attribute$throwException true) {
  1239.         // call security voter(s)
  1240.         if (false === $this->security->isGranted($attribute$entity)) {
  1241.             if ($throwException) {
  1242.                 throw new AccessDeniedException('Unauthorised access!');
  1243.             }
  1244.             return false;
  1245.         }
  1246.         return true;
  1247.     }
  1248.     private function userIsAdmin() {
  1249.         if($this->getUser() && ($this->getUser()->hasRole('ROLE_ADMIN') || $this->getUser()->hasRole('ROLE_SUPER_ADMIN')))
  1250.         {
  1251.             return true;
  1252.         }
  1253.         return false;
  1254.     }
  1255.     private function userIsImporter() {
  1256.         if($this->getUser() && ($this->getUser()->hasRole('ROLE_IMPORTER')))
  1257.         {
  1258.             return true;
  1259.         }
  1260.         return $this->userIsAdmin();
  1261.     }
  1262.      /**
  1263.       * Delete an object belonging to this hoard
  1264.       *
  1265.       * @Route("/{id}/ajax_delete_object/{object_id}", name="hoard_ajax_delete_object", methods={"POST"})
  1266.       */
  1267.       public function ajaxDeleteObject(Request $request$id$object_id)
  1268.       {
  1269.             $em $this->getDoctrine()->getManager();
  1270.             $hoard $em->getRepository('OxHoardBundle:Hoard')->find($id);
  1271.             //TODO - check user has permissions for this hoard
  1272.             $object $em->getRepository('OxHoardBundle:HObject')->find($object_id);
  1273.             $em->remove($object);
  1274.             $em->flush();
  1275.             return new JsonResponse(
  1276.                 array(
  1277.                     'deleted_object_id'=>$object->getId()
  1278.                 )
  1279.             );
  1280.       }
  1281.     /**
  1282.      * Add a new container to the hoard
  1283.      *
  1284.      * @Route("/{id}/ajax_add_container", name="hoard_ajax_add_container", methods={"POST"})
  1285.      */
  1286.      public function ajaxAddContainer(Request $request$id)
  1287.      {
  1288.          $em $this->getDoctrine()->getManager();
  1289.          $hoard $em->getRepository('OxHoardBundle:Hoard')->find($id);
  1290.          $container = new Container();
  1291.          $container->setHoard($hoard);
  1292.          $container->setCreationDate( new \DateTime("now"));
  1293.          $em->persist($container);
  1294.          $em->flush();
  1295.          return new JsonResponse(
  1296.              array(
  1297.                  'id'=>$container->getId(),
  1298.                  'title'=>$container->__toString(),
  1299.                  'description'=>$container->GetComment(),
  1300.                  'deleteURL'=>$this->generateUrl('hoard_ajax_delete_container',
  1301.                      array(
  1302.                          'id' => $hoard->getId(),
  1303.                          'container_id' => $container->getId(),
  1304.                          )
  1305.                  )
  1306.              )
  1307.          );
  1308.      }
  1309.      /**
  1310.       * Delete a container belonging to this hoard
  1311.       *
  1312.       * @Route("/{id}/ajax_delete_container/{container_id}", name="hoard_ajax_delete_container", methods={"POST"})
  1313.       */
  1314.       public function ajaxDeleteContainer(Request $request$id$container_id)
  1315.       {
  1316.             $em $this->getDoctrine()->getManager();
  1317.             $hoard $em->getRepository('OxHoardBundle:Hoard')->find($id);
  1318.             //TODO - check user has permissions for this hoard
  1319.             $container $em->getRepository('OxHoardBundle:Container')->find($container_id);
  1320.             $em->remove($container);
  1321.             $em->flush();
  1322.             return new JsonResponse(
  1323.                 array(
  1324.                     'deleted_object_id'=>$container->getId()
  1325.                 )
  1326.             );
  1327.       }
  1328.     /**
  1329.      * Generate values for Terminal Year based on Coin data in the hoard
  1330.      *    @Route("/generate/terminals/{id}", name="generate_terminals", methods={"GET"})
  1331.      */
  1332.     public function generateTerminals(Request $request)
  1333.     {
  1334.         $em $this->getDoctrine()->getManager();
  1335.         $hoardID $request->get('id');
  1336.         $query $em -> createQuery("SELECT MAX(c.startingDate) as maxStart, MAX(c.endingDate) as maxEnd FROM OxHoardBundle:Coin
  1337.                                     c WHERE c.hoard = :hoardID")
  1338.                         ->setParameter('hoardID'$hoardID.'%');
  1339.                         
  1340.         $results $query->getArrayResult();
  1341.         
  1342.         return new JsonResponse($results);
  1343.     }
  1344.     public function addRelatedCountries($hoard) {
  1345.       $countriesUK = ['England''Scotland' ,'Wales''Northern Ireland'];
  1346.       $countries $hoard->getCountries();
  1347.       $addUK false;
  1348.       $ukListed false;
  1349.       foreach($countries as $country) {
  1350.         if (in_array($country->getCountry(), $countriesUK))
  1351.         {
  1352.           $addUK true;
  1353.         }
  1354.         if ($country->getCountry() == "United Kingdom")
  1355.         {
  1356.           $ukListed true;
  1357.         }
  1358.       }
  1359.       if ($addUK && !$ukListed) {
  1360.         $em $this->getDoctrine()->getManager();
  1361.         $country $em->getRepository('OxHoardBundle:Country')->findByCountry("United Kingdom");
  1362.         $hoard->addCountry($country[0]);
  1363.       }
  1364.     }
  1365.     /**
  1366.      * Disaggregate a Hoard Coins entities.
  1367.      *
  1368.      * @Route("/{id}/disaggregate", name="hoard_disaggregate", methods={"POST"})
  1369.      */
  1370.     public function disaggregateAction(Request $request$id)
  1371.     {
  1372.         $form $this->createDisaggregateForm($idnull);
  1373.         $form->handleRequest($request);
  1374.         if ($form->isValid()) {
  1375.           $em $this->getDoctrine()->getManager();
  1376.           $hoard $em->getRepository('OxHoardBundle:Hoard')->find($id);
  1377.           $coins $hoard->getCoins();
  1378.           $this->checkAccess($hoard'edit');
  1379.           foreach ($coins as $entity) {
  1380.             if (!$entity) {
  1381.                 throw $this->createNotFoundException('Unable to find Coin entity.');
  1382.             }
  1383.             $quantity $entity->getQuantity();
  1384.             if ($quantity 1) {
  1385.               $entity->setQuantity(1);
  1386.               for ($i 1$i $quantity$i++) {
  1387.                   $clone = clone $entity;
  1388.                   //flag this as modified (even though it's technically being created, it's probably useful to track original creator in 'created')
  1389.                   $clone->setModified($this->getUser());
  1390.                   $em->persist($clone);
  1391.                   // clone all CoinAdditionalFields for the coin and set CoinAdditionalFields' oin to cloned coin
  1392.                   $additionalFieldsId $entity->getCoinAdditionalFields();
  1393.                   foreach ($additionalFieldsId as $additionalFieldId) {
  1394.                     $additionalField $em->getRepository('OxHoardBundle:CoinAdditionalField')->find($additionalFieldId);
  1395.                     $cloneAdditionalField = clone $additionalField;
  1396.                     $cloneAdditionalField->setCoin($clone);
  1397.                     $em->persist($cloneAdditionalField);
  1398.                   }
  1399.                   // clone all CoinReferences for the coin and set CoinReferences' coin to cloned coin
  1400.                   $referencesId $entity->getCoinReferences();
  1401.                   foreach ($referencesId as $referenceId) {
  1402.                     $reference $em->getRepository('OxHoardBundle:CoinReference')->find($referenceId);
  1403.                     $cloneReference = clone $reference;
  1404.                     $cloneReference->setCoin($clone);
  1405.                     $em->persist($cloneReference);
  1406.                   }
  1407.               } 
  1408.               $em->flush();
  1409.             }
  1410.         }
  1411.         return $this->redirect($this->generateUrl('hoard_edit', array('id' => $id)).'#coins');
  1412.       }
  1413.       return $this->redirect($this->generateUrl('hoard'));
  1414.     }
  1415.     /**
  1416.      * Creates a form to disaggregate the Coins of a Hoard by id.
  1417.      *
  1418.      * @param mixed $id The entity id
  1419.      *
  1420.      * @return \Symfony\Component\Form\Form The form
  1421.      */
  1422.     private function createDisaggregateForm($id)
  1423.     {
  1424.         $action $this->generateUrl('hoard_disaggregate', array('id' => $id));
  1425.         return $this->createFormBuilder()
  1426.             ->setAction($action)
  1427.             ->setMethod('POST')
  1428.             ->add('submit'SubmitType::class, array(
  1429.                 'label' => 'Disaggregate coins',
  1430.                 'attr' => array(
  1431.                     'class' => 'disaggregate-button'
  1432.                 )
  1433.             ))
  1434.             ->getForm()
  1435.             ;
  1436.     }
  1437. }