Skip to content

Commit

Permalink
Merge 7a9602e into 5a53606
Browse files Browse the repository at this point in the history
  • Loading branch information
Luc Wollants committed Oct 24, 2018
2 parents 5a53606 + 7a9602e commit 176fbb6
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 11 deletions.
26 changes: 26 additions & 0 deletions src/Common/Controllers/ResponseFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace VSV\GVQ_API\Common\Controllers;

use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\StreamedResponse;

class ResponseFactory
{
Expand Down Expand Up @@ -31,6 +32,31 @@ public function createCsvResponse(string $data, string $model): Response
return $response;
}

/**
* @param \Closure $callBack
* @param string $model
* @return StreamedResponse
*/
public function createStreamedCsvResponse(\Closure $callBack, string $model): StreamedResponse
{
$response = new StreamedResponse();

$response->headers->set('Content-Encoding', 'UTF-8');
$response->headers->set('Content-Type', 'application/csv; charset=UTF-8');
$response->headers->set('Content-Transfer-Encoding', 'binary');

$now = new \DateTime();
$fileName = $model.'_'.$now->format(\DateTime::ATOM).'.csv';
$response->headers->set(
'Content-Disposition',
'attachment; filename="'.$fileName.'"'
);

$response->setCallback($callBack);

return $response;
}

/**
* @param string $data
* @return string
Expand Down
68 changes: 57 additions & 11 deletions src/Contest/Controllers/ContestViewController.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Component\Translation\TranslatorInterface;
use VSV\GVQ_API\Common\Controllers\ResponseFactory;
use VSV\GVQ_API\Contest\Forms\ContestFormType;
use VSV\GVQ_API\Contest\Models\ContestParticipation;
use VSV\GVQ_API\Contest\Models\TieBreaker;
use VSV\GVQ_API\Contest\Repositories\TieBreakerRepository;
use VSV\GVQ_API\Contest\Service\ContestService;
Expand Down Expand Up @@ -166,24 +168,68 @@ public function contest(Request $request, string $quizId): Response
}

/**
* @return Response
* @return StreamedResponse
*/
public function export(): Response
{
$contestParticipations = $this->contestService->getAll();
$contestParticipationsAsCsv = $this->serializer->serialize(
$contestParticipations,
'csv'
);
$traversableContestParticipations = $this->contestService->getTraversableContestParticipations();

$response = $this->responseFactory->createCsvResponse(
$contestParticipationsAsCsv,
'contest_participations'
);
$callback = $this->createCallBackForStreamedCsvResponse($traversableContestParticipations);
$response = $this->responseFactory->createStreamedCsvResponse($callback, 'contest_participations');

return $response;
}

/**
* @param \Traversable $traversableContestParticipations
* @return \Closure
*/
private function createCallBackForStreamedCsvResponse(\Traversable $traversableContestParticipations): \Closure
{
return function () use ($traversableContestParticipations) {
$handle = fopen('php://output', 'r+');
fwrite(
$handle,
chr(0xFF).chr(0xFE).$this->convertEncoding('sep=,'.PHP_EOL)
);

$headerSet = false;
foreach ($traversableContestParticipations as $contestParticipation) {
/** @var ContestParticipation $contestParticipation */

$contestParticipationAsCsv = $this->serializer->serialize(
$contestParticipation,
'csv'
);
$headerValuesArray = explode("\n", $contestParticipationAsCsv);

if (!$headerSet) {
$header = $headerValuesArray[0];
fwrite(
$handle,
$this->convertEncoding($header.PHP_EOL)
);
$headerSet = true;
}

fwrite(
$handle,
$this->convertEncoding($headerValuesArray[1].PHP_EOL)
);
}
fclose($handle);
};
}

/**
* @param string $string
* @return string
*/
private function convertEncoding(string $string): string
{
return mb_convert_encoding($string, 'UTF-16LE', 'UTF-8');
}

/**
* @return FormInterface
*/
Expand All @@ -194,7 +240,7 @@ private function createContestForm(): FormInterface
$this->contestFormType->buildForm(
$formBuilder,
[
'translator' => $this->translator
'translator' => $this->translator,
]
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,38 @@ public function getAll(): ?ContestParticipations
return $this->toContestParticipations($contestParticipationEntities);
}

/**
* @return \Traversable
*/
public function getAllAsTraversable(): \Traversable
{
$batchSize = 10;
$firstResult = 0;

do {
$queryBuilder = $this->entityManager->createQueryBuilder();

$query = $queryBuilder->select('e')
->from(
'VSV\GVQ_API\Contest\Repositories\Entities\ContestParticipationEntity',
'e'
)
->orderBy('e.id', 'ASC')
->setMaxResults($batchSize)
->setFirstResult($firstResult)
->getQuery();

$currentBatchItemCount = 0;

foreach ($query->iterate() as $contestParticipationEntities) {
$currentBatchItemCount++;
yield $contestParticipationEntities[0]->toContestParticipation();
}

$firstResult += $batchSize;
} while ($currentBatchItemCount == $batchSize);
}

/**
* @param Year $year
* @param Email $email
Expand Down
5 changes: 5 additions & 0 deletions src/Contest/Repositories/ContestParticipationRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ public function getByYearAndEmailAndChannel(
*/
public function getAll(): ?ContestParticipations;

/**
* @return \Traversable
*/
public function getAllAsTraversable(): \Traversable;

/**
* @param Year $year
* @param Email $email
Expand Down
8 changes: 8 additions & 0 deletions src/Contest/Service/ContestService.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ public function getAll(): ?ContestParticipations
return $this->contestParticipationRepository->getAll();
}

/**
* @return \Traversable
*/
public function getTraversableContestParticipations(): \Traversable
{
return $this->contestParticipationRepository->getAllAsTraversable();
}

/**
* Can only participate if 11 or more and no previous participation for given channel.
*
Expand Down

0 comments on commit 176fbb6

Please sign in to comment.