<?php
namespace App\Controller;
use App\Entity\Period;
use App\Entity\ReporterPartner;
use App\Model\BarChartData;
use App\Model\DataSet;
use Carbon\Carbon;
use Carbon\CarbonPeriod;
use Doctrine\DBAL\Types\TextType;
use Doctrine\Persistence\ManagerRegistry;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Event\PostSubmitEvent;
use Symfony\Component\Form\Event\PreSubmitEvent;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
// use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Serializer\Encoder\JsonEncode;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Encoder\CsvEncoder;
use Symfony\Component\Serializer\Encoder\XmlEncoder;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;
class IaiDefaultController extends AbstractController
{
private ManagerRegistry $managerRegistry;
private LoggerInterface $logger;
public function __construct(ManagerRegistry $registry, LoggerInterface $logger)
{
$this->managerRegistry = $registry;
$this->logger = $logger;
}
public function testArray()
{
$barChartData = new BarChartData();
for ($i = 1; $i <= 12; ++$i) {
$barChartData->addLabel($i.'/2020');
}
$dataSet = new DataSet();
$dataSet->setLabel('Alumina (export)');
$dataSet->setHsCode(2818);
$dataSet->setBackgroundColor('#A293AB');
$dataSet->setIconClass('alumina');
$dataSet->setOrder(20);
$dataSet->addData(0);
$dataSet->addData(-700380);
$dataSet->addData(0);
$dataSet->addData(0);
$dataSet->addData(-1000);
$dataSet->addData(0);
$dataSet->addData(-10000000);
$dataSet->addData(0);
$dataSet->addData(0);
$dataSet->addData(0);
$dataSet->addData(0);
$dataSet->addData(0);
$barChartData->addDataset($dataSet);
$dataSet = new DataSet();
$dataSet->setLabel('Scrap (export)');
$dataSet->setHsCode(7602);
$dataSet->setBackgroundColor('#7DAA9D');
$dataSet->setIconClass('scrap');
$dataSet->setOrder(20);
$barChartData->addDataset($dataSet);
$dataSet = new DataSet();
$dataSet->setLabel('Extrusion (export)');
$dataSet->setHsCode(7604);
$dataSet->setBackgroundColor('#9C9E9C');
$dataSet->setIconClass('extrusion');
$dataSet->setOrder(20);
$dataSet->addData(-519);
$dataSet->addData(-8262);
$dataSet->addData(-2482);
$dataSet->addData(-684);
$dataSet->addData(0);
$dataSet->addData(0);
$dataSet->addData(-22);
$dataSet->addData(-6219);
$dataSet->addData(-5287);
$dataSet->addData(-4);
$dataSet->addData(0);
$dataSet->addData(0);
$barChartData->addDataset($dataSet);
return $barChartData;
}
/**
* @Route("/the-global-aluminium-cycle", name="iai_default")
* @Route("/iai/default", name="iai_default")
*/
public function index(Request $request, LoggerInterface $logger)
{
$formData = [];
$rpRepo = $this->managerRegistry->getRepository(ReporterPartner::class);
$periodRepo = $this->managerRegistry->getRepository(Period::class);
$countries = $rpRepo->getCountries();
$partners = $rpRepo->getPartners();
$products = $rpRepo->getProducts();
$productsFormValues = [];
foreach ($products as $k => $v) {
$productsFormValues[$v['product']] = $v['product'];
if ('Ingot (7601)' == $v['product']) {
$products[$k]['img'] = 'ingot';
}
if ('Scrap (7602)' == $v['product']) {
$products[$k]['img'] = 'scrap';
}
}
$flows = $rpRepo->getFlows();
$flowFormValues = [];
$flowFormValues['Import+Export'] = 'Import+Export';
foreach ($flows as $k => $v) {
$flowFormValues[$v['flow']] = $v['flow'];
}
$monthly_annual = ['Monthly' => 'monthly', 'Annual' => 'annual'];
$filterObj = $this->createFormBuilder()
->add('export', CheckboxType::class, [
'label' => 'Exports',
'data' => true,
])
->add('import', CheckboxType::class, [
'label' => 'Imports',
'data' => true,
])
->add('nettrade', CheckboxType::class, [
'label' => 'Net Trade',
'data' => true,
])
->add('monthly_annual', ChoiceType::class, [
'choices' => $monthly_annual,
'required' => true,
'expanded' => true,
'multiple' => false,
'placeholder' => false,
'data' => 'monthly',
])
->add('reporter', ChoiceType::class, [
'label' => 'Country',
'placeholder' => 'Choose an option',
'choices' => $countries,
'data' => 'China',
])
->add('tradingpartner', ChoiceType::class, [
'label' => 'Trading Partner',
'placeholder' => 'Choose an option',
'choices' => $partners,
'data' => 'USA',
])
->add('reportingcountry', ChoiceType::class, [
'label' => 'Reporting Country',
'placeholder' => 'Choose an option',
'choices' => ['China' => 'China', 'USA' => 'USA'],
'data' => 'China',
])
->add('periodFrom', DateType::class, [
'widget' => 'single_text',
'html5' => false,
'format' => 'MM/y',
'data' => new \DateTime('01/01/2020'),
'attr' => ['class' => 'js-datepicker'],
])
->add('periodTo', DateType::class, [
'widget' => 'single_text',
'html5' => false,
'format' => 'MM/y',
'data' => new \DateTime('12/01/2020'),
'attr' => ['class' => 'js-datepicker'],
])
->add('download', SubmitType::class, [
'label' => 'Download Data'
]);
$filterObj->addEventListener(
FormEvents::PRE_SUBMIT,
function (PreSubmitEvent $event): void {
$fData = $event->getData();
if (isset($fData['monthly_annual']) && $fData['monthly_annual'] == 'annual') {
$form = $event->getForm();
$form->remove('periodFrom');
$form->remove('periodTo');
$form->add('periodFrom', DateType::class, [
'widget' => 'single_text',
'html5' => false,
'format' => 'y',
'data' => new \DateTime('01/01/2020'),
'attr' => ['class' => 'js-datepicker'],
]);
$form->add('periodTo', DateType::class, [
'widget' => 'single_text',
'html5' => false,
'format' => 'y',
'data' => new \DateTime('12/01/2020'),
'attr' => ['class' => 'js-datepicker'],
]);
}
}
);
$logger->debug("Blub");
$logger->debug($products);
// ->add('from', TextType::class)
// ->add('to', TextType::class)
;
$filterObj->get('reportingcountry')->resetViewTransformers();
// $filterObj->get('export')->setData(true);
$filterForm = $filterObj->getForm();
$data = [];
$filterForm->handleRequest($request);
$isFirstRequest = true;
//$logger->debug($filterObj->getForm()->get('periodFrom')->getConfig()->getOptions());
if ($filterForm->isSubmitted()) { // && $filterForm->isValid()
$formData = $filterForm->getData();
$isFirstRequest = false;
} else {
// default values for Chart
$formData['export'] = 1;
$formData['import'] = 1;
$formData['nettrade'] = 1;
$formData['reporter'] = 'China';
$formData['tradingpartner'] = 'USA';
$formData['reportingcountry'] = 'China';
$formData['monthly_annual'] = 'monthly';
$formData['periodFrom'] = \DateTime::createFromFormat('m/Y', '01/2020');
$formData['periodTo'] = \DateTime::createFromFormat('m/Y', '12/2020');
}
if ($formData['monthly_annual'] != 'monthly' && $formData['monthly_annual'] != 'annual') {
$formData['monthly_annual'] = 'monthly';
}
if ($formData['monthly_annual'] == 'monthly') {
if ($formData['periodFrom'] == null) {
$formData['periodFrom'] = \DateTime::createFromFormat('m/Y', '01/2020');
}
if ($formData['periodTo'] == null) {
$formData['periodTo'] = \DateTime::createFromFormat('m/Y', '12/2020');;
}
}
if ($formData['monthly_annual'] == 'annual') {
if ($formData['periodFrom'] == null) {
$formData['periodFrom'] = \DateTime::createFromFormat('Y', '2008');
}
if ($formData['periodTo'] == null) {
$formData['periodTo'] = \DateTime::createFromFormat('Y', '2020');;
}
}
if ($filterForm->isSubmitted() && $filterForm->get('download')->isClicked()) {
return $this->provideCSVResponse($formData);
}
return $this->providePageResponse($formData, $countries, $partners, $products, $flows, $isFirstRequest, $filterForm);
}
/**
* @param $queryResult
* @param $periodType
* @param LoggerInterface $logger
* @return array
*/
public function prepareLabels($queryResult, $periodType, LoggerInterface $logger): array
{
$axisDates = [];
$axisDatesUnique = [];
/** @var ReporterPartner $rp */
foreach ($queryResult as $rp) {
foreach ($rp->getPeriods() as $pv) {
if ($periodType == 'monthly') {
$date = Carbon::create($pv->getYear(), $pv->getMonth());
$val = $date->format('m/Y');
}
else { // $formData['monthly_annual'] == 'annual'
$date = Carbon::create($pv->getYear());
$val = $date->format('Y');
}
if (!array_key_exists($val, $axisDatesUnique)) {
$axisDates[] = $date;
$axisDatesUnique[$val] = '';
}
}
}
usort($axisDates, function ($a, $b) {
if ($a->lessThan($b)) {
return -1;
}
else {
return 1;
}
});
if ($periodType == 'monthly') {
$dateFormat = 'm/Y';
}
else { // $formData['monthly_annual'] == 'annual'
$dateFormat = 'Y';
}
$axisLabels = array_map(function ($a) use ($dateFormat) {
return $a->format($dateFormat);
}, $axisDates);
return $axisLabels;
}
private function providePageResponse($formData, $countries, $partners, $products, $flows, $isFirstRequest, $filterForm) {
$fromDateHeadline = $formData['periodFrom']->format('Y');
$toDateHeadline = $formData['periodTo']->format('Y');
$reporter = $formData['reportingcountry'] ?: "-";
$reverseTradeFlow = false;
if ($formData['reporter'] == $formData['reportingcountry']) {
$tradingPartner = $formData['tradingpartner'] ?: "-";
}
else {
$tradingPartner = $formData['reporter'];
$reverseTradeFlow = true;
}
$export = $qExport = isset($formData['export']) && $formData['export'] == true;
$import = $qImport = isset($formData['import']) && $formData['import'] == true;
$netTrade = isset($formData['nettrade']) && $formData['nettrade'] == true;
if ($reverseTradeFlow) {
$qExport = $import;
$qImport = $export;
}
$rpRepo = $this->managerRegistry->getRepository(ReporterPartner::class);
$queryResult = $rpRepo->getQueryData($formData, $reporter, $tradingPartner, $qExport, $qImport, $netTrade);
$axisLabels = $this->prepareLabels($queryResult, $formData['monthly_annual'], $this->logger);
//$logger->debug("axl " . print_r($axisLabels, true));
$barChartData = new BarChartData();
$barChartData->setLabels(array_values($axisLabels));
/** @var ReporterPartner $rp */
foreach ($queryResult as $k => $rp) {
if ('Net Trade' == $rp->getTradeFlow()) {
continue;
}
$this->adjustTradeFlow($reverseTradeFlow, $rp);
$dataSet = $this->createNewDataSet($rp->getCommodityCode(), $rp->getTradeFlow());
$dataSet->setType('bar');
$dataSet->setBorderColor("#0000001a");
$dataSet->setOrder(20);
$periodValues = array_fill_keys($axisLabels, 0);
foreach ($rp->getPeriods() as $pk => $pv) {
if ($formData['monthly_annual'] == 'annual') {
$lbl = Carbon::create($pv->getYear())->format('Y');
} else { //$formData['monthly_annual'] == 'monthly'
$lbl = Carbon::create($pv->getYear(), $pv->getMonth())->format('m/Y');
}
if ('Exports' == $rp->getTradeFlow()) {
$periodValues[$lbl] = -$pv->getValue();
} else {
$periodValues[$lbl] = $pv->getValue();
}
}
$dataSet->setData(array_values($periodValues));
$barChartData->addDataset($dataSet);
}
if ($netTrade) {
$netTradeSet = $this->createNetTradeDataSet();
/** @var ReporterPartner $rp */
foreach ($queryResult as $k => $rp) {
if ('Net Trade' != $rp->getTradeFlow()) {
continue;
}
$periodValues = array_fill_keys($axisLabels, 0);
foreach ($rp->getPeriods() as $pk => $pv) {
if ($formData['monthly_annual'] == 'annual') {
$lbl = Carbon::create($pv->getYear())->format('Y');
} else { //$formData['monthly_annual'] == 'monthly'
$lbl = Carbon::create($pv->getYear(), $pv->getMonth())->format('m/Y');
}
if ($reverseTradeFlow) {
$periodValues[$lbl] = -$pv->getValue();
} else {
$periodValues[$lbl] = $pv->getValue();
}
}
$existingData = $netTradeSet->getData();
$addValues = array_values($periodValues);
if (empty($existingData)) {
$netTradeSet->setData(array_values($periodValues));
} else {
foreach ($existingData as $exKey => $exVal) {
$existingData[$exKey] += $addValues[$exKey];
}
$netTradeSet->setData($existingData);
}
}
$barChartData->addDataset($netTradeSet);
}
//$data = $rpRepo->getData($formData);
$encoders = [new JsonEncoder()];
$normalizers = [new ObjectNormalizer()];
$serializer = new Serializer($normalizers, $encoders);
$jsonContent = $serializer->serialize($barChartData, 'json');
// $jsonContent = $serializer->serialize($test, 'json');
//$csvContent = $serializer->serialize($data, 'csv');
// var_dump($csvContent);
//$response = new Response($serializer->serialize($barChartData, JsonEncoder::FORMAT, [JsonEncode::OPTIONS => JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT]));
// $response = new Response($serializer->serialize($test, JsonEncoder::FORMAT, [JsonEncode::OPTIONS => JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT]));
//$response->headers->set('Content-Type', 'application/json');
// return $response;
/*
echo '<pre>';
echo $jsonContent;
echo '</pre>';
exit;
*/
// $logger->debug('CUSTOM: '.var_export($data));
// return $response;
$prefix = '';
$binder = ' to ';
if ($import) {
$prefix = "Imports to";
$binder = ' from ';
}
if ($export) {
if ($prefix) {
$prefix .= "/";
}
$prefix .= "Exports from";
$binder = ' to ';
}
if ($netTrade) {
if ($prefix) {
$prefix .= "/";
}
$prefix .= "Net Imports to";
$binder = ' from ';
}
$title = $prefix . " " . ($formData['reporter'] ?: "-") . $binder . ($formData['tradingpartner'] ?: "-") . " reported by " . ($formData['reportingcountry'] ?: "-");
return $this->render('iai_default/index.html.twig', [
'countries' => $countries,
'partners' => $partners,
'products' => $products,
'flows' => $flows,
'filterForm' => $filterForm->createView(),
'title' => $title,
'reporter' => (isset($formData['reporter']) && !empty($formData['reporter']) ? $formData['reporter'] : 'China'),
'tradingpartner' => (isset($formData['tradingpartner']) && !empty($formData['tradingpartner']) ? $formData['tradingpartner'] : 'USA'),
'reportingCountry' => (isset($formData['reportingcountry']) && !empty($formData['reportingcountry']) ? $formData['reportingcountry'] : ''),
'fromDateHeadline' => $fromDateHeadline,
'toDateHeadline' => $toDateHeadline,
// 'data' => $data,
'data' => $jsonContent,
'isFirstRequest' => ($isFirstRequest ? 1 : 0),
'defaults' => $formData,
// 'response' => $jsonData,
]);
}
private function provideCSVResponse($formData) {
$reporter = $formData['reportingcountry'];
$reverseTradeFlow = false;
if ($formData['reporter'] == $formData['reportingcountry']) {
$tradingPartner = $formData['tradingpartner'];
}
else {
$tradingPartner = $formData['reporter'];
$reverseTradeFlow = true;
}
$export = isset($formData['export']) && $formData['export'] == true;
$import = isset($formData['import']) && $formData['import'] == true;
$netTrade = isset($formData['nettrade']) && $formData['nettrade'] == true;
if ($reverseTradeFlow) {
$exp = $import;
$imp = $export;
$export = $exp;
$import = $imp;
}
$rpRepo = $this->managerRegistry->getRepository(ReporterPartner::class);
$queryResult = $rpRepo->getQueryData($formData, $reporter, $tradingPartner, $export, $import, $netTrade);
$data = [];
/** @var ReporterPartner $rp */
foreach ($queryResult as $k => $rp) {
$this->adjustTradeFlow($reverseTradeFlow, $rp);
$row = [
'Country' => $formData['reporter'],
'Partner' => $formData['tradingpartner'],
'Reporter' => $formData['reportingcountry'],
'Trade Flow' => $rp->getTradeFlow(),
'Commodity Code (HS)' => $rp->getCommodityCode(),
'Commodity' => ReporterPartner::COMMODITY_CODE[$rp->getCommodityCode()],
'Unit' => 'kg',
];
foreach ($rp->getPeriods() as $pk => $pv) {
if ($formData['monthly_annual'] == 'annual') {
$key = Carbon::create($pv->getYear())->format('Y');
} else { //$formData['monthly_annual'] == 'monthly'
$key = Carbon::create($pv->getYear(), $pv->getMonth())->format('m/Y');
}
if ('Exports' == $rp->getTradeFlow()) {
$row[$key] = -$pv->getValue();
} else {
$row[$key] = $pv->getValue();
}
}
$data[] = $row;
}
$encoders = [new CsvEncoder()];
$normalizers = [new ObjectNormalizer()];
$serializer = new Serializer($normalizers, $encoders);
$csvContent = $serializer->serialize($data, CsvEncoder::FORMAT);
// var_dump($csvContent);
$response = new Response($csvContent);
$response->headers->set('Content-Type', 'text/csv');
return $response;
}
/**
* @param bool $reverseTradeFlow
* @param ReporterPartner $rp
* @return Period|mixed
*/
public function adjustTradeFlow(bool $reverseTradeFlow, ReporterPartner $rp)
{
if (!$reverseTradeFlow) {
return;
}
switch ($rp->getTradeFlow()) {
case 'Exports':
$rp->setTradeFlow('Imports');
break;
case 'Imports':
$rp->setTradeFlow('Exports');
break;
case 'Net Trade':
foreach ($rp->getPeriods() as $pv) {
$pv->setValue(-$pv->getValue());
}
break;
}
}
/**
* @param string $commodityCode
* @param string $tradeFlow
* @return DataSet
*/
public function createNewDataSet(string $commodityCode, string $tradeFlow): DataSet
{
$dataSet = new DataSet();
$dataSet->setLabel(ReporterPartner::COMMODITY_CODE[$commodityCode] . ' (' . $tradeFlow . ')');
$dataSet->setHsCode($commodityCode);
$dataSet->setBackgroundColor(ReporterPartner::BACKGROUNDCOLOR[$commodityCode]);
$dataSet->setIconClass(ReporterPartner::ICONCLASS[$commodityCode]);
return $dataSet;
}
public function createNetTradeDataSet(): DataSet
{
$dataSet = new DataSet();
$dataSet->setLabel('Net Trade');
$dataSet->setType('line');
$dataSet->setBackgroundColor('#000000');
$dataSet->setBorderColor('#000000');
$dataSet->setOrder(10);
return $dataSet;
}
}