src/Ox/HoardBundle/Controller/CoinController.php line 1244

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 Symfony\Component\Form\Extension\Core\Type\SubmitType;
  13. use Symfony\Component\Form\Extension\Core\Type\ButtonType;
  14. use App\Ox\HoardBundle\Entity\Coin;
  15. use App\Ox\HoardBundle\Form\CoinType;
  16. use App\Ox\HoardBundle\Entity\Image;
  17. use App\Ox\HoardBundle\Entity\CoinImage;
  18. /**
  19.  * coin controller.
  20.  *
  21.  * @Route("/coin")
  22.  */
  23. class CoinController extends AbstractController
  24. {
  25.     private $security;
  26.     public function __construct(Security $security)
  27.     {
  28.         $this->security $security;
  29.     }
  30.     /**
  31.      * Suggest obverse inscription
  32.      *    @Route("/suggest/obv/insc", name="suggest_obverse_inscription", methods={"GET"})
  33.      */
  34.     public function suggestObvInsc(Request $request)
  35.     {
  36.         $em $this->getDoctrine()->getManager();
  37.         $q $request->get('q');
  38.         $query $em -> createQuery("SELECT DISTINCT c.obverseInscription from OxHoardBundle:Coin c WHERE c.obverseInscription LIKE :query")
  39.                         ->setParameter('query'$q.'%');
  40.         $results $query->getArrayResult();
  41.         return new JsonResponse($results);
  42.     }
  43.     /**
  44.      * Suggest obverse mint mark
  45.      *    @Route("/suggest/obv/mint", name="suggest_obverse_mintmark", methods={"GET"})
  46.      */
  47.     public function suggestObvMint(Request $request)
  48.     {
  49.         $em $this->getDoctrine()->getManager();
  50.         $q $request->get('q');
  51.         $query $em -> createQuery("SELECT DISTINCT c.obverseMintMark from OxHoardBundle:Coin c WHERE c.obverseMintMark LIKE :query")
  52.                         ->setParameter('query'$q.'%');
  53.         $results $query->getArrayResult();
  54.         return new JsonResponse($results);
  55.     }
  56.     /**
  57.      * Suggest obverse description
  58.      *    @Route("/suggest/obv/desc", name="suggest_obverse_description", methods={"GET"})
  59.      */
  60.     public function suggestObvDesc(Request $request)
  61.     {
  62.         $em $this->getDoctrine()->getManager();
  63.         $q $request->get('q');
  64.         $query $em -> createQuery("SELECT DISTINCT c.obverseDescription from OxHoardBundle:Coin c WHERE c.obverseDescription LIKE :query")
  65.                         ->setParameter('query'$q.'%');
  66.         $results $query->getArrayResult();
  67.         return new JsonResponse($results);
  68.     }
  69.   /**
  70.      * Suggest reverse inscription
  71.      *    @Route("/suggest/rev/insc", name="suggest_reverse_inscription", methods={"GET"})
  72.      */
  73.     public function suggestRevInsc(Request $request)
  74.     {
  75.         $em $this->getDoctrine()->getManager();
  76.         $q $request->get('q');
  77.         $query $em -> createQuery("SELECT DISTINCT c.reverseInscription from OxHoardBundle:Coin c WHERE c.reverseInscription LIKE :query")
  78.                         ->setParameter('query'$q.'%');
  79.         $results $query->getArrayResult();
  80.         return new JsonResponse($results);
  81.     }
  82.     /**
  83.      * Suggest reverse mint mark
  84.      *    @Route("/suggest/rev/mint", name="suggest_reverse_mintmark", methods={"GET"})
  85.      */
  86.     public function suggestRevMint(Request $request)
  87.     {
  88.         $em $this->getDoctrine()->getManager();
  89.         $q $request->get('q');
  90.         $query $em -> createQuery("SELECT DISTINCT c.reverseMintMark from OxHoardBundle:Coin c WHERE c.reverseMintMark LIKE :query")
  91.                         ->setParameter('query'$q.'%');
  92.         $results $query->getArrayResult();
  93.         return new JsonResponse($results);
  94.     }
  95.     /**
  96.      * Suggest reverse description
  97.      *    @Route("/suggest/rev/desc", name="suggest_reverse_description", methods={"GET"})
  98.      */
  99.     public function suggestRevDesc(Request $request)
  100.     {
  101.         $em $this->getDoctrine()->getManager();
  102.         $q $request->get('q');
  103.         $query $em -> createQuery("SELECT DISTINCT c.reverseDescription from OxHoardBundle:Coin c WHERE c.reverseDescription LIKE :query")
  104.                         ->setParameter('query'$q.'%');
  105.         $results $query->getArrayResult();
  106.         return new JsonResponse($results);
  107.     }
  108.     /**
  109.      * Suggest person based on period
  110.      * @Route("/suggest/person", name="suggest_person", methods={"GET"})
  111.      */
  112.     public function suggestPerson(Request $request)
  113.     {
  114.         $em $this->getDoctrine()->getManager();
  115.         $pid $request->get('period');
  116.         $reignids_str $request->get('reign');
  117.         $q $request->get('q');
  118.         $queryBuilder $em->createQueryBuilder();
  119.         if(isset($reignids_str)) {
  120.             $reignids explode(","$reignids_str);
  121.             $queryBuilder->select('ocre, p')
  122.             ->from('OxHoardBundle:OcreLookup''ocre')
  123.             ->leftJoin('ocre.reign''r')
  124.             ->leftJoin('ocre.person''p')
  125.             ->where('r.id IN (:reigns)')
  126.             ->setParameter('reigns'$reignids);
  127.             
  128.             if($q) {
  129.                 $queryBuilder->andWhere('r.reign LIKE :query')
  130.                 ->setParameter('query''%'.$q.'%');
  131.             }
  132.             
  133.             $query $queryBuilder->getQuery();
  134.             $ocres $query->getArrayResult();
  135.             //extract just the reigns
  136.             $results = [];
  137.             foreach($ocres as $ocre) {
  138.                 if(!in_array($ocre['person'], $results)) {
  139.                     $results[] = $ocre['person'];
  140.                 }
  141.             }
  142.           }
  143.           if(!isset($reignids_str) || empty($results)) {
  144.             $queryBuilder $em->createQueryBuilder();
  145.             $queryBuilder->select('p')
  146.             ->from('OxHoardBundle:Person''p');
  147.             
  148.             if($pid) {
  149.                 $queryBuilder->leftJoin('p.period1''period1')
  150.                 ->leftJoin('p.period2''period2')
  151.                 ->leftJoin('p.period3''period3')
  152.                 ->where('period1.id = :period')
  153.                 ->orWhere('period2.id = :period')
  154.                 ->orWhere('period3.id = :period')
  155.                 ->orWhere('period1.id is NULL AND period2.id is NULL AND period3.id is NULL')
  156.                 ->setParameter('period'$pid)
  157.                 ->orderBy('p.person''ASC')
  158.                 ;
  159.             }
  160.             
  161.             if($q) {
  162.                 $queryBuilder->andWhere('p.person LIKE :query')
  163.                 ->setParameter('query''%'.$q.'%');
  164.             }
  165.             
  166.             
  167.             $query $queryBuilder->getQuery();
  168.             
  169.             $results $query->getArrayResult();
  170.             
  171.             $response = [];
  172.         }
  173.         foreach($results as $result) {
  174.             if($result['title']) {
  175.                 $result['person'] = $result['person'].' ('.$result['title'].')';
  176.             }
  177.             $response[] = $result;
  178.         }
  179.         return new JsonResponse($response);
  180.     }
  181.     /**
  182.      * Suggest reign based on period
  183.      * @Route("/suggest/reign", name="suggest_reign", methods={"GET"})
  184.      */
  185.     public function suggestReign(Request $request)
  186.     {
  187.         $em $this->getDoctrine()->getManager();
  188.         $pid $request->get('period');
  189.         $personids_str $request->get('person');
  190.         $q $request->get('q');
  191.         $queryBuilder $em->createQueryBuilder();
  192.         if(isset($personids_str)) {
  193.             $personids explode(","$personids_str);
  194.             $queryBuilder->select('ocre, r')
  195.             ->from('OxHoardBundle:OcreLookup''ocre')
  196.             ->leftJoin('ocre.reign''r')
  197.             ->leftJoin('ocre.person''p')
  198.             ->where('p.id IN (:persons)')
  199.             ->setParameter('persons'$personids);
  200.             if($q) {
  201.                 $queryBuilder->andWhere('r.reign LIKE :query')
  202.                 ->setParameter('query''%'.$q.'%');
  203.             }
  204.             $query $queryBuilder->getQuery();
  205.             $ocres $query->getArrayResult();
  206.             //extract just the reigns
  207.             $results = [];
  208.             foreach($ocres as $ocre) {
  209.                 if(!in_array($ocre['reign'], $results)) {
  210.                     $results[] = $ocre['reign'];
  211.                 }
  212.             }
  213.         }
  214.         if(!isset($personids_str) || empty($results)) {
  215.             $queryBuilder $em->createQueryBuilder();
  216.             //suggest based on period
  217.             $queryBuilder->select('r')
  218.             ->from('OxHoardBundle:Reign''r');
  219.             
  220.             if($pid) {
  221.                 $queryBuilder->leftJoin('r.period1''period1')
  222.                 ->leftJoin('r.period2''period2')
  223.                 ->where('period1.id = :period')
  224.                 ->orWhere('period2.id = :period')
  225.                 ->orWhere('period1.id is NULL AND period2.id is NULL')
  226.                 ->setParameter('period'$pid)
  227.                 ->orderBy('r.startDate''ASC')
  228.                 ->addOrderBy('r.endDate''ASC');
  229.             }
  230.             
  231.             if($q) {
  232.                 $queryBuilder->andWhere('r.reign LIKE :query')
  233.                 ->setParameter('query''%'.$q.'%');
  234.             }
  235.             
  236.             $query $queryBuilder->getQuery();
  237.             
  238.             $results $query->getArrayResult();
  239.         }
  240.         return new JsonResponse($results);
  241.     }
  242.     /**
  243.      * Suggest mint based on period
  244.      * @Route("/suggest/mint", name="suggest_mint", methods={"GET"})
  245.      */
  246.     public function suggestMint(Request $request)
  247.     {
  248.         $em $this->getDoctrine()->getManager();
  249.         $pid $request->get('period');
  250.         $q $request->get('q');
  251.         $queryBuilder $em->createQueryBuilder();
  252.         $queryBuilder->select('m')
  253.                         ->from('OxHoardBundle:Mint''m');
  254.         if($pid) {
  255.             $queryBuilder->leftJoin('m.period1''period1')
  256.                 ->leftJoin('m.period2''period2')
  257.                 ->leftJoin('m.period3''period3')
  258.                 ->leftJoin('m.period4''period4')
  259.                 ->where('period1.id = :period')
  260.                 ->orWhere('period2.id = :period')
  261.                 ->orWhere('period3.id = :period')
  262.                 ->orWhere('period4.id = :period')
  263.                 ->orWhere('period1.id is NULL AND period2.id is NULL AND period3.id is NULL AND period4.id is NULL')
  264.                 ->setParameter('period'$pid)
  265.                 ->orderBy('m.mint''ASC');
  266.         }
  267.         if($q) {
  268.             $queryBuilder->andWhere('m.mint LIKE :query')
  269.                 ->setParameter('query''%'.$q.'%');
  270.         }
  271.         $query $queryBuilder->getQuery();
  272.         $results $query->getArrayResult();
  273.         return new JsonResponse($results);
  274.     }
  275.     /**
  276.      * @Route("/ocre", name="ocre_autocomplete", methods={"GET"})
  277.      */
  278.     public function getOcreLookup(Request $request) {
  279.         //get the parameters
  280.         $reign_id $request->get('reign');
  281.         $person_id $request->get('person');
  282.         $mint_id $request->get('mint');
  283.         
  284.         if(!$reign_id) {
  285.             return new JsonResponse(array('error' => 'no reign id supplied'));
  286.         }
  287.         if(!$person_id) {
  288.             return new JsonResponse(array('error' => 'no person id supplied'));
  289.         }
  290.         
  291.         $em $this->getDoctrine()->getManager();
  292.         
  293.         $reign $em->getRepository('OxHoardBundle:Reign')->find($reign_id);
  294.         if(!$reign) {
  295.             //return error
  296.             return new JsonResponse(array('error' => 'reign not found'));
  297.         }
  298.         
  299.         $person $em->getRepository('OxHoardBundle:Person')->find($person_id);
  300.         if(!$person) {
  301.             return new JsonResponse(array('error' => 'person not found'));
  302.         }
  303.         
  304.         //if a mint was specified get the mint
  305.         if($mint_id) {
  306.             $mint $em->getRepository('OxHoardBundle:Mint')->find($mint_id);
  307.             if(!$mint) {
  308.                 return new JsonResponse(array('error' => 'mint not found'));
  309.             }
  310.         }
  311.         
  312.         //first try lookup without mint
  313.         $result $em->getRepository('OxHoardBundle:OcreLookup')->findBy(array(
  314.             'reign' => $reign,
  315.             'person' => $person
  316.         ));
  317.         $count count($result);
  318.         // return new JsonResponse($count);
  319.         if($count == 1) {
  320.             $lookup $result[0];
  321.         } else if($count 1) {
  322.             $lookup null;
  323.         } else {
  324.             //multiple matches, try with mint, or ask user to supply if necessary
  325.             if($mint_id && $mint) {
  326.                 $result $em->getRepository('OxHoardBundle:OcreLookup')->findBy(array(
  327.                     'reign' => $reign,
  328.                     'person' => $person,
  329.                     'mint' => $mint
  330.                 ));
  331.                 $count count($result);
  332.                 if($count == 1) {
  333.                     $lookup $result[0];
  334.                 } else if($count 1) {
  335.                     $lookup null;
  336.                 } else {
  337.                     //multiple matches, user should specify mint
  338.                     return new JsonResponse(array(
  339.                         'error' => 'multiple matches'
  340.                         'message' => 'Multiple matches were found even with mint included. Check OCRE table.'
  341.                     ));
  342.                 }
  343.             } else {
  344.                 return new JsonResponse(array(
  345.                     'error' => 'mint required'
  346.                     'message' => 'Multiple matches were found but a mint was not specified, please specify a mint and try again.'
  347.                 ));
  348.             }
  349.         }
  350.         
  351.         $return = array();
  352.         $return['reign'] = $reign->getReign();
  353.         $return['person'] = $person->getPerson();
  354.         if($mint_id && $mint) {
  355.             $return['mint'] = $mint->getMint();
  356.         }
  357.         if(!$lookup) {
  358.             $return['error'] = 'no results found';
  359.         } else {
  360.             $return['ocre'] = $lookup->getOcrePrefix();
  361.         }
  362.         return new JsonResponse($return);
  363.     }
  364.     /**
  365.      * @Route("/suggest/coin", name="suggest_coin", methods={"GET"})
  366.      */
  367.     public function suggestCoin(Request $request)
  368.     {
  369.         //first try to find a coin with hoard_id = null
  370.         $qb_noHoard $this->GetCoinMatchQueryBuilder($request);
  371.         $qb_noHoard->andWhere("c.hoard IS NULL");
  372.         $coins $qb_noHoard->getQuery()->getResult();
  373.         if(count($coins) == 0) {
  374.             //none with null hoard - instead find most recent one
  375.             $qb_mostRecent $this->GetCoinMatchQueryBuilder($request);
  376.             $qb_mostRecent->orderBy('c.modifiedDate''DESC');
  377.             $qb_mostRecent->setMaxResults(1);
  378.             $coins $qb_mostRecent->getQuery()->getResult();
  379.         }
  380. //        echo '<pre>'; print_r($qb->getDql()); echo '</pre>';
  381.         if(count($coins) > 0) {
  382.             $coin $coins[0];
  383.             $mints $coin->getMints();
  384.             $mintsArray = array();
  385.             foreach ($mints as $mint) {
  386.                 $mintsArray[] = $mint->getId();
  387.             }
  388.             $denominations $coin->getDenominations();
  389.             $denominationsArray = array();
  390.             foreach ($denominations as $denomination) {
  391.                 $denominationsArray[] = $denomination->getId();
  392.             }
  393.             $persons $coin->getPersons();
  394.             $personsArray = array();
  395.             foreach ($persons as $person) {
  396.                 $personsArray[] = $person->getId();
  397.             }
  398.             $reigns $coin->getReigns();
  399.             $reignsArray = array();
  400.             foreach ($reigns as $reign) {
  401.                 $reignsArray[] = $reign->getId();
  402.             }
  403.             if ($coins) {
  404.                 $response['success'] = true;
  405.                 $response['coin'] = array(
  406.                     'id' => $coin->getId(),
  407.                     'startingDate' => $coin->getStartingDate(),
  408.                     'endingDate' => $coin->getEndingDate(),
  409.                     'dateText' => $coin->getDateText(),
  410.                     'issue' => $coin->getIssue(),
  411.                     'officina' => $coin->getOfficina(),
  412.                     'obverseInscription' => $coin->getObverseInscription(),
  413.                     'obverseMintMark' => $coin->getObverseMintMark(),
  414.                     'obverseDescription' => $coin->getObverseDescription(),
  415.                     'reverseInscription' => $coin->getReverseInscription(),
  416.                     'reverseMintMark' => $coin->getReverseMintMark(),
  417.                     'reverseDescription' => $coin->getReverseDescription(),
  418.                     'persons' => $personsArray,
  419.                     'reigns' => $reignsArray,
  420.                     'mints' => $mintsArray,
  421.                     'denominations' => $denominationsArray,
  422.                 );
  423.             }
  424.         } else {
  425.             $response['success'] = false;
  426.             $response['msg'] = 'No matching coin was found';
  427.         }
  428.         return new JsonResponse($response);
  429.     }
  430.     private function GetCoinMatchQueryBuilder($request) {
  431.         $em $this->getDoctrine()->getManager();
  432.         $periodId $request->query->get('period');
  433.         $reignIds $request->query->get('reigns');
  434.         $personIds $request->query->get('persons');
  435.         $denominationIds $request->query->get('denominations');
  436.         $mintIds $request->query->get('mints');
  437.         $refId $request->query->get('ref');
  438.         $refStr $request->query->get('refStr');
  439.         $qb $em->createQueryBuilder();
  440.         $isRomanRepublicCoin $periodId == 20;
  441.         $qb->select('c')
  442.             ->from('OxHoardBundle:Coin''c');
  443.         $response = array();
  444.         if($periodId) {
  445.             $qb->leftJoin('c.period''period')
  446.                 ->andWhere('period.id = :period')
  447.                 ->setParameter('period'$periodId);
  448.             //different rules if roman republic coin
  449.             if($isRomanRepublicCoin ) {
  450.                 $response['isRomanRepublicCoin'] = true;
  451.             }
  452.         } else {
  453.             //period is required
  454.             $response['success'] = false;
  455.             $response['msg'] = 'No period supplied';
  456.             return new JsonResponse($response);
  457.         }
  458.         $qb->leftJoin('c.coinReferences''coinReferences');
  459.         if($refId) {
  460.             $qb->leftJoin('coinReferences.reference''reference')
  461.                 ->andWhere('reference.id = :coinRef')
  462.                 ->setParameter('coinRef'$refId);
  463.         } else {
  464.             //reference is required
  465.             $response['success'] = false;
  466.             $response['msg'] = 'No reference supplied';
  467.             return new JsonResponse($response);
  468.         }
  469.         if ($refStr) {
  470.             $qb->andWhere('coinReferences.reference_str = :refStr')
  471.                 ->setParameter('refStr'$refStr);
  472.         } else {
  473.             //reference string is required
  474.             $response['success'] = false;
  475.             $response['msg'] = 'No reference string has been entered';
  476.             return new JsonResponse($response);
  477.         }
  478.         $params = array();
  479.         if($isRomanRepublicCoin) {
  480.             //no check on mints etc
  481.         } else {
  482.             //check for matches against the mints, persons, reigns, denominations for non republican era coins
  483.             if ($reignIds) {
  484.                 //construct a query to search through all reigns
  485.                 $qb->leftJoin('c.reigns''reign');
  486.                 $reignIdsArray explode(','$reignIds);
  487.                 $subQuery "";
  488.                 foreach ($reignIdsArray as $index => $reignId) {
  489.                     $id intval($reignId);
  490.                     $reign $em->getRepository('OxHoardBundle:Reign')->find($reignId);
  491.                     if ($reign) {
  492.                         if ($index 0) {
  493.                             $subQuery .= " OR ";
  494.                         }
  495.                         $subQuery .= 'reign.id = :reign_' $index;
  496.                         $params['reign_' $index] = $reign;
  497.                     }
  498.                 }
  499.                 $qb->andWhere($subQuery);
  500.             }
  501.             if ($mintIds) {
  502.                 //construct a query to search through all mints
  503.                 $qb->leftJoin('c.mints''mint');
  504.                 $mintIdsArray explode(','$mintIds);
  505.                 $subQuery "";
  506.                 foreach ($mintIdsArray as $index => $mintId) {
  507.                     $id intval($mintId);
  508.                     $mint $em->getRepository('OxHoardBundle:Mint')->find($mintId);
  509.                     if ($mint) {
  510.                         if ($index 0) {
  511.                             $subQuery .= " OR ";
  512.                         }
  513.                         $subQuery .= 'mint.id = :mint_' $index;
  514.                         $params['mint_' $index] = $mint;
  515.                     }
  516.                 }
  517.                 $qb->andWhere($subQuery);
  518.             }
  519.             if ($personIds) {
  520.                 //construct a query to search through all persons
  521.                 $qb->leftJoin('c.persons''person');
  522.                 $personIdsArray explode(','$personIds);
  523.                 $subQuery "";
  524.                 foreach ($personIdsArray as $index => $personId) {
  525.                     $id intval($personId);
  526.                     $person $em->getRepository('OxHoardBundle:Person')->find($personId);
  527.                     if ($person) {
  528.                         if ($index 0) {
  529.                             $subQuery .= " OR ";
  530.                         }
  531.                         $subQuery .= 'person.id = :person_' $index;
  532.                         $params['person_' $index] = $person;
  533.                     }
  534.                 }
  535.                 $qb->andWhere($subQuery);
  536.             }
  537.             if ($denominationIds) {
  538.                 //construct a query to search through all denominations
  539.                 $qb->leftJoin('c.denominations''denomination');
  540.                 $denominationIdsArray explode(','$denominationIds);
  541.                 $subQuery "";
  542.                 foreach ($denominationIdsArray as $index => $denominationId) {
  543.                     $id intval($denominationId);
  544.                     $denomination $em->getRepository('OxHoardBundle:Denomination')->find($denominationId);
  545.                     if ($denomination) {
  546.                         if ($index 0) {
  547.                             $subQuery .= " OR ";
  548.                         }
  549.                         $subQuery .= 'denomination.id = :denomination_' $index;
  550.                         $params['denomination_' $index] = $denomination;
  551.                     }
  552.                 }
  553.                 $qb->andWhere($subQuery);
  554.             }
  555.         }
  556.         //Only match coins where inscription/description fields are not null
  557.         $qb->andWhere('c.obverseInscription IS NOT NULL')
  558.             ->andWhere('c.obverseDescription IS NOT NULL')
  559.             ->andWhere('c.reverseInscription IS NOT NULL')
  560.             ->andWhere('c.reverseDescription IS NOT NULL');
  561.         foreach($params as $key=>$value) {
  562.             $qb->setParameter($key$value);
  563.         }
  564.         return $qb;
  565.     }
  566.     /**
  567.      * Lists all Coin entities.
  568.      *
  569.      * @Route("/", name="coin", methods={"GET"})
  570.      * @Template()
  571.      */
  572.     public function indexAction(Request $request)
  573.     {
  574.         $limit 20;
  575.         $em $this->getDoctrine()->getManager();
  576.         $em->getFilters()->enable('softdeleteable');
  577.         $dql 'SELECT c FROM OxHoardBundle:Coin c';
  578.         $query $em->createQuery($dql)
  579.             ->setFirstResult(0)
  580.             ->setMaxResults($limit);
  581.         $paginator $this->get('knp_paginator');
  582.         $pagination $paginator->paginate(
  583.             $query,
  584.             $request->query->getInt('page'1)/*page number*/,
  585.             $limit/*limit per page*/
  586.         );
  587.         // parameters to template
  588.         return $this->render('@OxHoardBundle/coin/list.html.twig', array('pagination' => $pagination));
  589.     }
  590.     /**
  591.      * //coins are created via the hoard controller's ajax_add_coin method (or via disaggregate)
  592.      * @Route("coin_create")
  593.      * @Template()
  594.      */
  595.     public function createAction()
  596.     {
  597.         return array();
  598.     }
  599.     /**
  600.      * Deletes a Coin entity.
  601.      *
  602.      * @Route("/{id}", name="coin_delete", methods={"DELETE"})
  603.      */
  604.     public function deleteAction(Request $request$id)
  605.     {
  606.         $form $this->createDeleteForm($idnull);
  607.         $form->handleRequest($request);
  608.         if ($form->isValid()) {
  609.             $em $this->getDoctrine()->getManager();
  610.             $entity $em->getRepository('OxHoardBundle:Coin')->find($id);
  611.             $this->checkAccess($entity'delete');
  612.             //referer will be passed in the URL. If it isn't present, get it from the header.
  613.             $referer $request->get('referer');
  614.             if(!$referer)
  615.             {
  616.                 $referer $request->headers->get('referer');
  617.             }
  618.             if (!$entity) {
  619.                 throw $this->createNotFoundException('Unable to find Coin entity.');
  620.             }
  621.             $em->remove($entity);
  622.             $em->flush();
  623.             /// No longer returning to the hoard, since the update coin page is now always opened in a new tab,
  624.             // redirecting to the hoard is a bad idea.
  625.             // //redirect to original referer, with #coins at the end, so that the page knows to open to an appropriate position
  626.             // return $this->redirect($referer.'#coins');
  627.             return $this->redirect($this->generateUrl('hoard'));
  628.         }
  629.         return $this->redirect($this->generateUrl('hoard'));
  630.     }
  631.     /**
  632.      * Disaggregate a Coin entity.
  633.      *
  634.      * @Route("/{id}/disaggregate", name="coin_disaggregate", methods={"POST"})
  635.      */
  636.     public function disaggregateAction(Request $request$id)
  637.     {
  638.         $form $this->createDisaggregateForm($idnull);
  639.         $form->handleRequest($request);
  640.         if ($form->isValid()) {
  641.             $em $this->getDoctrine()->getManager();
  642.             $entity $em->getRepository('OxHoardBundle:Coin')->find($id);
  643.             $this->checkAccess($entity'delete');
  644.             
  645.             //referer will be passed in the URL. If it isn't present, get it from the header.
  646.             $referer $request->get('referer');
  647.             if(!$referer)
  648.             {
  649.                 $referer $request->headers->get('referer');
  650.             }
  651.             
  652.             if (!$entity) {
  653.                 throw $this->createNotFoundException('Unable to find Coin entity.');
  654.             }
  655.             $quantity $entity->getQuantity();
  656.             if ($quantity 1) {
  657.               $entity->setQuantity(1);
  658.               for ($i 1$i $quantity$i++) {
  659.                   $clone = clone $entity;
  660.                   //flag this as modified (even though it's technically being created, it's probably useful to track original creator in 'created')
  661.                   $clone->setModified($this->getUser());
  662.                   $em->persist($clone);
  663.                   // clone all CoinAdditionalFields for the coin and set CoinAdditionalFields' oin to cloned coin
  664.                   $additionalFieldsId $entity->getCoinAdditionalFields();
  665.                   foreach ($additionalFieldsId as $additionalFieldId) {
  666.                     $additionalField $em->getRepository('OxHoardBundle:CoinAdditionalField')->find($additionalFieldId);
  667.                     $cloneAdditionalField = clone $additionalField;
  668.                     $cloneAdditionalField->setCoin($clone);
  669.                     $em->persist($cloneAdditionalField);
  670.                   }
  671.                   // clone all CoinReferences for the coin and set CoinReferences' coin to cloned coin
  672.                   $referencesId $entity->getCoinReferences();
  673.                   foreach ($referencesId as $referenceId) {
  674.                     $reference $em->getRepository('OxHoardBundle:CoinReference')->find($referenceId);
  675.                     $cloneReference = clone $reference;
  676.                     $cloneReference->setCoin($clone);
  677.                     $em->persist($cloneReference);
  678.                   }
  679.               } 
  680.               $em->flush();
  681.             }
  682.             
  683.             
  684.             $request->getSession()
  685.                 ->getFlashBag()
  686.                 ->add('success''Coin record has been disaggregated.');
  687.                 
  688.             /// No longer returning to the hoard, since the update coin page is now always opened in a new tab,
  689.             // redirecting to the hoard is a bad idea.
  690.             // //redirect to original referer, with #coins at the end, so that the page knows to open to an appropriate position
  691.             // return $this->redirect($referer.'#coins');
  692.             return $this->redirect($this->generateUrl('coin_show', array('id' => $id)));
  693.         }
  694.         return $this->redirect($this->generateUrl('hoard'));
  695.     }
  696.     /**
  697.      * Remove an existing coin image
  698.      * @Route("/{id}/ajax_remove_image/{typeId}", name="ajax_remove_coin_image", methods={"POST"})
  699.      */
  700.     public function removeImage($id$typeId)
  701.     {
  702.         $em=$this->getDoctrine()->getManager();
  703.         $coin $em->getRepository('OxHoardBundle:Coin')->find($id);
  704.         $this->checkAccess($coin'edit');
  705.         $type $em->getRepository('OxHoardBundle:CoinImageType')->find($typeId);
  706.         $coinImage $em->getRepository('OxHoardBundle:CoinImage')->findOneBy(array(
  707.             'coin' => $coin,
  708.             'type' => $type
  709.         ));
  710.         $em->remove($coinImage);
  711.         $em->flush();
  712.         return new JsonResponse( array(
  713.             'success' => 1,
  714.             'type' => $typeId
  715.         ));
  716.     }
  717.     /**
  718.      * Adds a new image file, creating an Image entity, a CoinImage entity
  719.      *
  720.      * @Route("/{id}/ajax_add_image/{typeId}", methods={"POST"})
  721.      */
  722.     public function addImage(Request $request$id$typeId)
  723.     {
  724.         $em $this->getDoctrine()->getManager();
  725.         
  726.         $file $request->files->get('image');
  727.         $coin $em->getRepository('OxHoardBundle:Coin')->find($id);
  728.         $this->checkAccess($coin'edit');
  729.         //validate the file - TODO
  730.         
  731.         //build new filename
  732.         $type $em->getRepository('OxHoardBundle:CoinImageType')->find($typeId);
  733.         
  734.         $ext $file->guessExtension();
  735.         $fileName $id.$type->getAbbreviation().'.'.$ext;
  736.         
  737.         //move to desired location with desired name
  738.         $destPath $this->getPermanentCoinImageUploadDir();
  739.         $file $file->move($destPath$fileName);
  740.         
  741.         //create Image
  742.         $image = new Image();
  743.         $image->setFileName($fileName);
  744.         $em->persist($image);
  745.         
  746.         //find existing coinImage of that type for that coin
  747.         $coinImage $em->getRepository('OxHoardBundle:CoinImage')->findOneBy(array(
  748.             'coin' => $coin,
  749.             'type' => $type
  750.         ));
  751.        
  752.         //create CoinImage with appropriate type
  753.         if(!$coinImage)
  754.         {
  755.             $coinImage = new CoinImage();
  756.             $coinImage->setType($type);
  757.             $coinImage->setCoin($coin);
  758.             $em->persist($coinImage);
  759.         }
  760.         $coinImage->setImage($image);
  761.         
  762.         //flush em
  763.         //mark as unvalidated since it has changed
  764.         if(!$this->userIsAdmin())
  765.         {
  766.             if($coin->getHoard())
  767.             {
  768.                 $coin->getHoard()->markUnvalidatedByAdmin();
  769.             }
  770.         }
  771.         $em->flush();
  772.         
  773.         $typeAbbr $type->getAbbreviation();
  774.         //fudge for the fact that symfony doesn't like the empty string in its routes.
  775.         if($typeAbbr == '') { $typeAbbr 'c'; }
  776.         
  777.         $url $this->get('router')->generate('coin_image', array(
  778.             'coin_id' => $id,
  779.             'coin_image_type' => $typeAbbr,
  780.             'ext' => $ext
  781.         ));
  782.         //return response
  783.         return new JsonResponse(
  784.             array('file' => $fileName'url' => $url)
  785.         );
  786.     }
  787.     /**
  788.      * @Route("/{id}/edit", name="coin_edit", methods={"GET"})
  789.      * @Template()
  790.      */
  791.     public function editAction(Request $request$id)
  792.     {
  793.         $em $this->getDoctrine()->getManager();
  794.         //referer will be passed in the URL. If it isn't present, get it from the header.
  795.         $referer $request->get('referer');
  796.         if(!$referer)
  797.         {
  798.             $referer $request->headers->get('referer');
  799.         }
  800.         $coin $em->getRepository('OxHoardBundle:Coin')->find($id);
  801.         if (!$coin
  802.         {
  803.             throw $this->createNotFoundException('Unable to find Coin entity.');
  804.         }
  805.         $this->checkAccess($coin'edit');
  806.         $editForm $this->createEditForm($coin$referer);
  807.         $deleteForm $this->createDeleteForm($id$referer);
  808.         $disaggregateForm $this->createDisaggregateForm($id$referer);
  809.         $isAjax $request->isXmlHttpRequest();
  810.         $template = ($isAjax '@OxHoardBundle/coin/edit_form.html.twig' '@OxHoardBundle/coin/edit.html.twig');
  811.         $referenceTypes $em->createQuery('SELECT rt FROM OxHoardBundle:ReferenceType rt ORDER BY rt.referenceType')->getResult();
  812.         return $this->render($template, array(
  813.             'ajax' => $isAjax,
  814.             'coin' => $coin,
  815.             'edit_form' => $editForm->createView(),
  816.             'delete_form' => $deleteForm->createView(),
  817.             'disaggregate_form' => $disaggregateForm->createView(),
  818.             'images' => $this->getImages($coin),
  819.             'reference_types' => $referenceTypes
  820.         ));
  821.     }
  822.     /****
  823.      * Get a list of image file names/ids for the given coin entity
  824.      */
  825.     private function getImages(Coin $entity) {
  826.         $coinImages $entity->getCoinImages();
  827.         
  828.         $images = array();
  829.                 
  830.         $folder '/uploads/images/coins/';
  831.         
  832.         $obverseCoinImage $coinImages->filter(
  833.             function($entry) {
  834.                 $type $entry->getType();
  835.                 return $entry->getType()->getAbbreviation()=="o";
  836.             }  
  837.         )->first();
  838.         if($obverseCoinImage)
  839.         {
  840.             $obverseImage $obverseCoinImage->getImage();
  841.             if($obverseImage)
  842.             {
  843.                 $images['obverse'] = $folder.$obverseImage->getFilename();
  844.             }
  845.         }
  846.         
  847.         $reverseCoinImage $coinImages->filter(
  848.             function($entry) {
  849.                 return $entry->getType()->getAbbreviation()=="r";
  850.             }  
  851.         )->first();
  852.         if($reverseCoinImage)
  853.         {
  854.             $reverseImage $reverseCoinImage->getImage();
  855.             if($reverseImage)
  856.             {
  857.                 $images['reverse'] = $folder.$reverseImage->getFilename();
  858.             }
  859.         }
  860.         
  861.         $bothCoinImage $coinImages->filter(
  862.             function($entry) {
  863.                 return $entry->getType()->getAbbreviation()=="";
  864.             }  
  865.         )->first();
  866.         if($bothCoinImage)
  867.         {
  868.             $bothImage $bothCoinImage->getImage();
  869.             if($bothImage)
  870.             {
  871.                 $images['both'] = $folder.$bothImage->getFilename();
  872.             }
  873.         }
  874.         
  875.         return $images;
  876.     }
  877.     
  878.     /**
  879.      * Creates a form to delete a Coin entity by id.
  880.      *
  881.      * @param mixed $id The entity id
  882.      *
  883.      * @return \Symfony\Component\Form\Form The form
  884.      */
  885.     private function createDeleteForm($id$referer)
  886.     {
  887.         $action $this->generateUrl('coin_delete', array('id' => $id));
  888.         if($referer) {
  889.             $action .= '?referer='.$referer;
  890.         }
  891.         return $this->createFormBuilder()
  892.             ->setAction($action)
  893.             ->setMethod('DELETE')
  894.             ->add('submit'ButtonType::class, array(
  895.                 'label' => 'Delete this coin',
  896.                 'attr' => array(
  897.                     'class' => 'delete-button btn btn-danger'
  898.                 )
  899.             ))
  900.             ->getForm()
  901.             ;
  902.     }
  903.     /**
  904.      * Creates a form to disaggregate a Coin group by id.
  905.      *
  906.      * @param mixed $id The entity id
  907.      *
  908.      * @return \Symfony\Component\Form\Form The form
  909.      */
  910.     private function createDisaggregateForm($id$referer)
  911.     {
  912.         $action $this->generateUrl('coin_disaggregate', array('id' => $id));
  913.         if($referer) {
  914.             $action .= '?referer='.$referer;
  915.         }
  916.         return $this->createFormBuilder()
  917.             ->setAction($action)
  918.             ->setMethod('POST')
  919.             ->add('submit'SubmitType::class, array(
  920.                 'label' => 'Disaggregate coins',
  921.                 'attr' => array(
  922.                     'class' => 'disaggregate-button'
  923.                 )
  924.             ))
  925.             ->getForm()
  926.             ;
  927.     }
  928.     /**
  929.      * Creates a form to edit a Coin entity.
  930.      *
  931.      * @param Coin $entity The entity
  932.      *
  933.      * @return \Symfony\Component\Form\Form The form
  934.      */
  935.     private function createEditForm(Coin $entity$referer)
  936.     {
  937.         
  938.         $containers $entity->getHoard()->getContainers();
  939.         $layers = new \Doctrine\Common\Collections\ArrayCollection();
  940.         foreach($containers as $container)
  941.         {
  942.             $containerLayers $container->getLayers();
  943.             foreach($containerLayers as $layer)
  944.             {
  945.                 $layers[] = $layer;
  946.             }
  947.         }
  948.         $action $this->generateUrl('coin_update',
  949.             array(
  950.                 'id' => $entity->getId()
  951.             ));
  952.         if($referer) {
  953.             $action .= '?referer='.$referer;
  954.         }
  955.         $form $this->createForm(CoinType::class, $entity, array(
  956.             'action' => $action,
  957.             'containers' => $containers,
  958.             'layers' => $layers,
  959.             'em' => $this->getDoctrine()->getManager(),
  960.         ));
  961.         $form->add('submit'SubmitType::class, array(
  962.             'label' => 'Update',
  963.             'attr' => array('class' => 'update-button')
  964.             ));
  965.         return $form;
  966.     }
  967.     /**
  968.      * Edits an existing Coin entity.
  969.      *
  970.      * @Route("/{id}", name="coin_update", methods={"POST"}) PUT doesn't seem to work...
  971.      * @Template("@OxHoardBundle/coin/edit.html.twig")
  972.      */
  973.     public function updateAction(Request $request$id)
  974.     {
  975.         $em $this->getDoctrine()->getManager();
  976.         $em->getFilters()->enable('softdeleteable');
  977.         $coin $em->getRepository('OxHoardBundle:Coin')->find($id);
  978.         $this->checkAccess($coin'edit');
  979.         if (!$coin) {
  980.             throw $this->createNotFoundException('Unable to find Coin entity.');
  981.         }
  982.         //referer will be passed in the URL. If it isn't present, get it from the header.
  983.         $referer $request->get('referer');
  984.         if(!$referer)
  985.         {
  986.             $referer $request->headers->get('referer');
  987.         }
  988.         $deleteForm $this->createDeleteForm($id$referer);
  989.         $editForm $this->createEditForm($coin$referer);
  990.         $editForm->handleRequest($request);
  991.         if ($editForm->isValid()) {
  992.                         
  993.             //mark as unvalidated since it has changed
  994.             if(!$this->userIsAdmin())
  995.             {
  996.                 if($coin->getHoard())
  997.                 {
  998.                     $coin->getHoard()->markUnvalidatedByAdmin();
  999.                 }
  1000.             }
  1001.                         
  1002.             //persist images
  1003.             $coinImages $coin->getCoinImages();
  1004.             foreach($coinImages as $coinImage)
  1005.             {
  1006.                 if($coinImage->getImage()){
  1007.                     $em->persist($coinImage);
  1008.                 }
  1009.             }
  1010.             
  1011.             //persist references
  1012.             $coinReferences $coin->getCoinReferences();
  1013.             foreach($coinReferences as $ref)
  1014.             {
  1015.                 if ($ref->getReference() === null && $ref->getReferenceStr() === null && $ref->getComment() === null) {
  1016.                   $ref->setDeleted(true);
  1017.                 }
  1018.                 if($ref->getDeleted())
  1019.                 {
  1020.                     //do soft delete
  1021.                     //persist deleted flag
  1022.                     $em->persist($ref);
  1023.                     //clear the link with the coin
  1024.                     $ref->setCoin(null);
  1025.                     //flush before removing
  1026.                     $em->flush();
  1027.                     $em->remove($ref);
  1028.                 }
  1029.                 else 
  1030.                 {
  1031.                     $ref->setCoin($coin);
  1032.                     $em->persist($ref);
  1033.                 }
  1034.             }
  1035.             
  1036.             //persist additional fields
  1037.             $coinAdditionalFields $coin->getCoinAdditionalFields();
  1038.             foreach($coinAdditionalFields as $field)
  1039.             {
  1040.                 if($field->getDeleted())
  1041.                 {
  1042.                     //do soft delete
  1043.                     //persist deleted flag
  1044.                     $em->persist($field);
  1045.                     //clear link with coin
  1046.                     $field->setCoin(null);
  1047.                     $em->flush();
  1048.                     $em->remove($field);
  1049.                 }
  1050.                 else 
  1051.                 {
  1052.                     $field->setCoin($coin);
  1053.                     $em->persist($field);
  1054.                 }
  1055.             }
  1056.             
  1057.             $coin->setModified($this->getUser());
  1058.             $em->flush();
  1059.             $request->getSession()
  1060.                 ->getFlashBag()
  1061.                 ->add('success''Coin has been updated');
  1062.             /// No longer returning to the hoard, since the update coin page is now always opened in a new tab,
  1063.             // redirecting to the hoard is a bad idea.
  1064.             // //redirect to original referer, with #coins at the end, so that the page knows to open to an appropriate position
  1065.             // return $this->redirect($referer.'#coins');
  1066.             return $this->redirect($this->generateUrl('coin_show', array('id' => $id)));
  1067.         }
  1068.         else {
  1069.             $request->getSession()
  1070.                 ->getFlashBag()
  1071.                 ->add('error''Error updating coin!');
  1072.         }
  1073.         $referenceTypes $em->createQuery('SELECT rt FROM OxHoardBundle:ReferenceType rt ORDER BY rt.referenceType')->getResult();
  1074.         return array(
  1075.             'coin'      => $coin,
  1076.             'edit_form'   => $editForm->createView(),
  1077.             'delete_form' => $deleteForm->createView(),
  1078.             'images' => $this->getImages($coin),
  1079.             'reference_types' => $referenceTypes
  1080.         );
  1081.     }
  1082.     /**
  1083.      * Finds and displays a coin entity.
  1084.      *
  1085.      * @Route("/{id}", name="coin_show", methods={"GET"})
  1086.      * @Template()
  1087.      */
  1088.     public function showAction($id)
  1089.     {
  1090.         $em $this->getDoctrine()->getManager();
  1091.         $coin $em->getRepository('OxHoardBundle:Coin')->find($id);
  1092.         $this->checkAccess($coin'view_coins');
  1093.         if (!$coin) {
  1094.             throw $this->createNotFoundException('Unable to find Coin entity.');
  1095.         }
  1096.         // $deleteForm = $this->createDeleteForm($id);
  1097.         $images $this->getImages($coin);
  1098.         return array(
  1099.             'coin'      => $coin,
  1100.             'images' => $images,
  1101.             // 'delete_form' => $deleteForm->createView(),
  1102.         );
  1103.     }
  1104.     
  1105.     /**
  1106.      * checks permission of user's current request
  1107.      *
  1108.      * @param mixed $entity The entity being validated
  1109.      *
  1110.      * @param string $attribute - 'view' or 'edit' or 'delete'
  1111.      * @return boolean
  1112.      *
  1113.      * @throws \Symfony\Component\Security\Core\Exception\AccessDeniedException
  1114.      */
  1115.     private function checkAccess($entity$attribute) {
  1116.         // call security voter(s)
  1117.         if (false === $this->security->isGranted($attribute$entity->getHoard())) {
  1118.             throw new AccessDeniedException('Unauthorised access!');
  1119.         }
  1120.         return true;
  1121.     }
  1122.     
  1123.     private function userIsAdmin() {
  1124.         if($this->getUser() && ($this->getUser()->hasRole('ROLE_ADMIN') || $this->getUser()->hasRole('ROLE_SUPER_ADMIN')))
  1125.         {
  1126.             return true;
  1127.         }
  1128.         return false;
  1129.     }
  1130.     private function getPermanentCoinImageUploadDir() {
  1131.         return '/srv/hoards_coin_images';
  1132.     }
  1133. }