src/Controller/Admin/Player/VouchersController.php line 95

Open in your IDE?
  1. <?php
  2. namespace App\Controller\Admin\Player;
  3. use App\Controller\Admin\AbstractVoucherController;
  4. use App\Entity\Client;
  5. use App\Entity\Player;
  6. use App\Entity\PlayerGroup;
  7. use App\Entity\VoucherGroup;
  8. use App\Form\Admin\VoucherCreateType;
  9. use App\Form\Admin\VoucherImportType;
  10. use App\Repository\ClientRepository;
  11. use App\Repository\PlayerRepository;
  12. use App\Repository\VoucherRepository;
  13. use App\Validation\Admin\VoucherCreateContract;
  14. use App\Validation\Admin\VoucherImportContract;
  15. use DateTime;
  16. use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
  17. use Doctrine\ORM\EntityManagerInterface;
  18. use DomainException;
  19. use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache;
  20. use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
  21. use Symfony\Component\Form\FormError;
  22. use Symfony\Component\HttpFoundation\File\File;
  23. use Symfony\Component\HttpFoundation\Request;
  24. use Symfony\Component\HttpFoundation\RequestStack;
  25. use Symfony\Component\Routing\Annotation\Route;
  26. use Symfony\Component\Security\Core\Security;
  27. use Symfony\Component\Validator\Validator\ValidatorInterface;
  28. use Twig\Environment;
  29. /**
  30.  * @Route("/players/{slug}/vouchers")
  31.  * @IsGranted("ROLE_CLIENT")
  32.  * @Cache(mustRevalidate=true)
  33.  */
  34. class VouchersController extends AbstractVoucherController
  35. {
  36.   private ValidatorInterface $validator;
  37.   private VoucherRepository $voucherRepo;
  38.   public function __construct(ClientRepository $clientrepoEntityManagerInterface $emRequestStack $stackEnvironment $twigSecurity $securityValidatorInterface $validatorVoucherRepository $voucherRepo) {
  39.     parent::__construct($clientrepo$em$stack$twig$security);
  40.     $this->validator $validator;
  41.     $this->voucherRepo $voucherRepo;
  42.   }
  43.   /**
  44.    * @Route("/")
  45.    */
  46.   public function list(Request $r$slugPlayerRepository $playerrepo) {
  47.     $player $playerrepo->getBySlug($slug);
  48.     if(!$player) {
  49.       throw $this->createNotFoundException();
  50.     }
  51.     $client $this->ensureClient($player->getClient());
  52.     $this->setPlayerContext($player);
  53.     // Handle creation form
  54.     $createForm $this->createForm(VoucherCreateType::class, new VoucherCreateContract(), [
  55.       'client' => $client,
  56.       'player' => $player,
  57.     ]);
  58.     $createForm->handleRequest($r);
  59.     $importForm $this->createForm(VoucherImportType::class);
  60.     $importForm->handleRequest($r);
  61.     if($createForm->isSubmitted() && $createForm->isValid()) {
  62.       $this->voucherRepo->createVouchers($player$createForm->getData(), $this->getUser());
  63.       $this->addFlash('success'"Voucher(s) created");
  64.       return $this->redirectToRoute("app_admin_player_vouchers_list", ['slug' => $slug]);
  65.     }
  66.     if($importForm->isSubmitted() && $importForm->isValid()) {
  67.       $file $importForm->get("file")->getData();
  68.       try {
  69.         $codes $this->getCodesFromFile($player$client$file);
  70.         $this->voucherRepo->importVouchers($player$this->getUser(), $codes);
  71.         $this->addFlash('success'count($codes)." voucher(s) imported");
  72.         return $this->redirectToRoute("app_admin_player_vouchers_list", ['slug' => $slug]);
  73.       } catch(DomainException $ex) {
  74.         $importForm->get('file')->addError(new FormError($ex->getMessage()));
  75.       } catch(UniqueConstraintViolationException $ex) {
  76.         preg_match("/Duplicate entry '[0-9]+-([^']+)'/"$ex->getMessage(), $matches);
  77.         $duplicate $matches[1] ?? 'unkwnown';
  78.         $importForm->get('file')->addError(new FormError("Can't import file, one or more codes already exists ({$duplicate})"));
  79.       }
  80.     }
  81.     return $this->renderVoucherList('admin/player/vouchers.html.twig'$createForm$importForm);
  82.   }
  83.   protected function getCodesFromFile(Player $playerClient $clientFile $file): array {
  84.     $fp fopen($file->getPathname(), 'r');
  85.     $columns fgetcsv($fp128';');
  86.     if(!is_array($columns) || !count($columns)) {
  87.       throw new DomainException("Aucune colonne dans le fichier");
  88.     }
  89.     $allColumns = ['type''code''group'];
  90.     $requiredColumns = ['type''code'];
  91.     if(!$player->getIsLive()) {
  92.       $allColumns array_merge($allColumns, ['replay''validitystart''validityend']);
  93.       $requiredColumns[] = "replay";
  94.     }
  95.     
  96.     // Compute mappings
  97.     $mapping = [];
  98.     foreach($columns as $i => $col) {
  99.       $mapped false;
  100.       foreach($allColumns as $name) {
  101.         if(strtolower(trim($col)) == $name) {
  102.           $mapping[$name] = $i;
  103.           $mapped true;
  104.           break;
  105.         }
  106.       }
  107.       if(!$mapped) {
  108.         throw new \DomainException("Can't map column '{$col}'");
  109.       }
  110.     }
  111.     // Check required columns
  112.     foreach($requiredColumns as $name) {
  113.       if(!isset($mapping[$name])) {
  114.         throw new DomainException("Missing {$name} column");
  115.       }
  116.     }
  117.     
  118.     // Get list of voucher groups
  119.     // Todo: don't load all voucher groups, get on need basis while discovering codes
  120.     $groups array_reduce($client->getVoucherGroups()->toArray(), fn($resultVoucherGroup $group) => $result + [$group->getName() => $group], []);
  121.     $defaultGroup $client->getDefaultGroup();
  122.     $line 1;
  123.     $codes = [];
  124.     while(!feof($fp)) {
  125.       $data fgetcsv($fp128';');
  126.       // Ignore empty lines
  127.       if(!$data || !count($data)) {
  128.         continue;
  129.       }
  130.       if(count($data) != count($mapping)) {
  131.         throw new DomainException("Bad number of columns in line en ligne $line");
  132.       }
  133.       $code = new VoucherImportContract();
  134.       $code->type trim($data[$mapping['type']]);
  135.       $code->code trim($data[$mapping['code']]);
  136.       if(!isset($mapping['group'])) {
  137.         $code->group $defaultGroup;
  138.       } else {
  139.         $code->group $groups[trim($data[$mapping['group']])] ?? null;
  140.         if(!$code->group) {
  141.           throw new DomainException("Inexistant voucher group {$data[$mapping['group']]} in line {$line}");
  142.         }
  143.       }
  144.       if(isset($mapping['validitystart'])) {
  145.         $code->dateStart DateTime::createFromFormat("Y-m-d"trim($data[$mapping['validitystart']]));
  146.       }
  147.       if(isset($mapping['validityend'])) {
  148.         $code->dateEnd DateTime::createFromFormat("Y-m-d"trim($data[$mapping['validityend']]));
  149.       }
  150.       
  151.       $errors $this->validator->validate($code);
  152.       if(count($errors)) {
  153.         throw new \DomainException("Error line {$line} for code {$code->code}{$errors[0]->getMessage()}");
  154.       }
  155.       $codes[$code->code] = $code;
  156.       $line++;
  157.     }
  158.     
  159.     return $codes;
  160.   }
  161. }