<?php
namespace App\Controller;
use App\Activity\Canopy;
use App\Entity\Log;
use App\Entity\Option;
use App\Helper\Company;
use setasign\Fpdi\Fpdi;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Asset\Packages;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\Mailer\Mailer;
use Symfony\Component\Mime\Email;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Yaml\Yaml;
use Symfony\Contracts\Translation\TranslatorInterface;
use App\Xml\CanopyXml;
class CanopyController extends AbstractController
{
/**
* @Route("/verriere", name="canopy_home")
*
* Show disposition popup
*/
public function selectDisposition(Canopy $canopy): Response
{
return $this->render("home/index.html.twig", ["popup" => "popup_select_canopy"]);
}
/**
* @Route("/verriere/conception", name="canopy_select_concept")
*
* Show tool popup
*/
public function selectTool(Canopy $canopy): Response
{
return $this->render("home/index.html.twig", ["popup" => "popup_select_canopy"]);
}
/**
* @Route("/verriere/builder", name="canopy_tool_concept")
*
* Show tool popup
*/
public function selectBuilder(Canopy $canopy): Response
{
return $this->render("home/index.html.twig", ["popup" => "popup_tool_canopy"]);
}
/**
* @Route("/ajax/verriere/disposition", name="canopy_set_disp", methods={"POST"})
*
* Set disposition when selected
*/
public function setDisposition(Session $session, Request $request): \Symfony\Component\HttpFoundation\JsonResponse
{
$content = json_decode($request->getContent(), true);
$token = uniqid();
$session->set("token", $token);
$session->set("canopy.disp", intval($content['disp']));
return $this->json(['disp' => $session->get("canopy.disp")]);
}
/**
* @Route("/verriere/conception/panneau-{step}", requirements={"number": "\d+", "step": "\d+"}, name="canopy_concept_step")
* @Route("/verriere/conception/{tool}", name="canopy_concept")
* @Route("/verriere/conception/{tool}/panneau-{step}", requirements={"number": "\d+", "step": "\d+"}, name="canopy_concept_pannel_step")
*
* Display tool
*/
public function showTool(Canopy $canopy, Session $session, $projectDir, $step = null, $tool = null, \App\Helper\Log $logHelper): Response
{
$nextStep = null;
// If no disposition set
if(!$session->has("canopy.disp") || !$session->has('token')) {
return $this->redirectToRoute("home");
}
$token = $session->get("token");
$number = $session->get('canopy.disp');
if($step === null) {
$step = 1;
}
// Check if we have a next step for this disposition and the current step
if($canopy->hasNextStep($number, $step)) {
$nextStep = $step + 1;
}
// Find disposition name and index
$disposition = "";
$dispositionIndex = 0;
foreach($canopy->getDispositions() as $i => $dispo) {
if($i === intval($number)) {
$disposition = $dispo;
$dispositionIndex = $i;
}
}
// Create token file
$configFile = sprintf("%s/var/tokens/%s.yaml", $projectDir, $token);
if(!file_exists($configFile) || $step === 1) {
if (!file_exists(dirname($configFile))) {
mkdir(dirname($configFile), 0777, true);
}
file_put_contents($configFile, Yaml::dump(["disposition" => $dispositionIndex, "time" => time()]));
}
$width = 0;
$height = 0;
$configOptions = [];
$reference = null;
// If we're not in the first step, find first step configuration
if($step > 1) {
$config = Yaml::parseFile($configFile);
// Only use $config[0] as it's the first step
// Copy 'option' to 'options' as it was misspelled sometimes
if(!array_key_exists('options', $config[0])) {
$config[0]['options'] = $config[0]['option'];
}
$configOptions = $config[0]['options'];
$width = $config[0]['dimensions']['width'];
$height = $config[0]['dimensions']['height'];
$reference = $config[0]['reference'];
}
else {
if ($number == 1) {
$this->getDoctrine()->getRepository(Log::class)->addLog($this->getUser(), 'START_SIMPLE_CANOPY');
}
else {
$this->getDoctrine()->getRepository(Log::class)->addLog($this->getUser(), 'START_CORNER_CANOPY');
}
}
$keys = ['frameType', 'color', 'rempl'];
foreach($keys as $key) {
if (array_key_exists($key, $configOptions) && gettype($configOptions[$key]) == "string") {
$configOptions[$key] = $this->getDoctrine()->getRepository(Option::class)->find($configOptions[$key]);
}
}
$modules = ['canopy_simple', 'canopy_corner'];
$options = [];
foreach ($this->getUser()->getCompany()->getOptions() as $option) {
foreach ($option->getModules() as $module) {
if (in_array($module->getName(), $modules)) {
$options[$option->getType()][] = $option;
break;
}
}
}
return $this->render("activities/canopy/tool.html.twig",
[
'token' => $token,
'step' => $step,
'nextStep' => $nextStep,
'isFirstStep' => $step == 1,
'config' => [
'options' => $configOptions,
'width' => $width,
'height' => $height
],
"nbStep" => $number,
'disposition' => $disposition,
'rempl' => [],
'tool' => $tool,
"panel" => $canopy->getPanelNameByDisposition($number, $step),
"options" => $options,
"reference" => $reference
]);
}
/**
* @Route("/verriere/resultat", name="canopy_final")
*
* Show resume of conception
*/
public function finalStep(Canopy $canopy, Session $session, $projectDir): Response
{
$token = $session->get('token');
$configFile = sprintf("%s/var/tokens/%s.yaml", $projectDir, $token);
$config = Yaml::parseFile($configFile);
// Remove unnecessary information
unset($config['time']);
$dispositionIndex = $config['disposition'];
unset($config['disposition']);
if(array_key_exists("pdf", $config)) {
unset($config['pdf']);
}
$dispositions = $canopy->getDispositions();
$disposition = $dispositions[$dispositionIndex];
$pannels = [];
foreach($config as $pannel) {
if ($pannel['options']) {
$options = &$pannel['options'];
$keys = ['frameType', 'color', 'rempl'];
foreach($keys as $key) {
if (array_key_exists($key, $options) && gettype($options[$key]) == "string") {
$options[$key] = $this->getDoctrine()->getRepository(Option::class)->find($options[$key]);
}
}
}
$pannels[intval($pannel['step'])] = $pannel;
$pannels[intval($pannel['step'])]['name'] = $canopy->getPanelNameByDisposition($dispositionIndex, intval($pannel['step']));
}
ksort($pannels);
return $this->render("activities/canopy/final.html.twig", ['pannels' => $pannels, 'disposition' => $disposition]);
}
/**
* @Route("/verriere/pdf", name="canopy_pdf")
*
* Print PDF
*/
public function printPdf(Canopy $canopy, Session $session, $projectDir, Packages $pathPackage, Company $company, TranslatorInterface $translator): \Symfony\Component\HttpFoundation\BinaryFileResponse
{
$token = $session->get('token');
$configFile = sprintf("%s/var/tokens/%s.yaml", $projectDir, $token);
$config = Yaml::parseFile($configFile);
$dispositionIndex = $config['disposition'];
if(!array_key_exists('pdf', $config)) {
if ($dispositionIndex == 1) {
$this->getDoctrine()->getRepository(Log::class)->addLog($this->getUser(), 'END_SIMPLE_CANOPY');
}
else {
$this->getDoctrine()->getRepository(Log::class)->addLog($this->getUser(), 'END_CORNER_CANOPY');
}
}
return $this->file($this->getPdf($canopy, $session, $projectDir, $pathPackage, $company, $translator), "verriere.pdf", ResponseHeaderBag::DISPOSITION_INLINE);
}
/**
* @Route("/verriere/xml", name="canopy_xml")
*
* Print XML
*/
public function printXML(Canopy $canopy, Session $session, $projectDir, Packages $pathPackage, Company $company, TranslatorInterface $translator): \Symfony\Component\HttpFoundation\BinaryFileResponse
{
$token = $session->get('token');
$configFile = sprintf("%s/var/tokens/%s.yaml", $projectDir, $token);
$config = Yaml::parseFile($configFile);
$dispositionIndex = $config['disposition'];
if(!array_key_exists('xml', $config)) {
if ($dispositionIndex == 1) {
$this->getDoctrine()->getRepository(Log::class)->addLog($this->getUser(), 'END_SIMPLE_CANOPY');
}
else {
$this->getDoctrine()->getRepository(Log::class)->addLog($this->getUser(), 'END_CORNER_CANOPY');
}
}
return $this->file($this->getXML($canopy, $session, $projectDir, $pathPackage, $company, $translator), "verriere.xml", ResponseHeaderBag::DISPOSITION_ATTACHMENT);
}
/**
* @Route("/verriere/email", name="canopy_email")
*
* Send PDF by mail
*/
public function emailPdf($email, Canopy $canopy, Session $session, $projectDir, Packages $pathPackage, Company $company, Mailer $mailer, TranslatorInterface $translator): RedirectResponse
{
$message = new Email();
$message->from($email)
->to($email)
->subject("Nouvelle demande de Verrière")
->attachFromPath($this->getPdf($canopy, $session, $projectDir, $pathPackage, $company, $translator), 'Verrière');
$mailer->send($message);
return $this->redirectToRoute("canopy_final");
}
/**
* Generate PDF
*
* @param Canopy $canopy
* @param Session $session
* @param $projectDir
* @param Packages $pathPackage
* @param Company $company
* @return string
* @throws \setasign\Fpdi\PdfParser\CrossReference\CrossReferenceException
* @throws \setasign\Fpdi\PdfParser\Filter\FilterException
* @throws \setasign\Fpdi\PdfParser\PdfParserException
* @throws \setasign\Fpdi\PdfParser\Type\PdfTypeException
* @throws \setasign\Fpdi\PdfReader\PdfReaderException
*/
private function getPdf(Canopy $canopy, Session $session, $projectDir, Packages $pathPackage, Company $company, TranslatorInterface $translator): string
{
$token = $session->get('token');
$user = $this->getUser();
$configFile = sprintf("%s/var/tokens/%s.yaml", $projectDir, $token);
$config = Yaml::parseFile($configFile);
$dayDate = (new \DateTime())->format("Y-m-d");
// Remove unnecessary keys
unset($config['time']);
$dispositionIndex = $config['disposition'];
unset($config['disposition']);
unset($config['xml']);
// Unlink previously created file if there is one
if(array_key_exists("pdf", $config)) {
if(file_exists($config['pdf'])) {
unlink($config['pdf']);
}
unset($config['pdf']);
}
$dispositions = $canopy->getDispositions();
$disposition = $dispositions[$dispositionIndex];
$pannels = [];
foreach($config as $pannel) {
$pannels[intval($pannel['step'])] = $pannel;
// Only show prices if activated
if($user->isTarif()) {
$pannels[intval($pannel['step'])]['price'] = $canopy->handleAjax("price", $pannel);
} else {
$pannels[intval($pannel['step'])]['price'] = ['prices' => [], 'price' => null];
}
$pannels[intval($pannel['step'])]['name'] = $canopy->getPanelNameByDisposition($dispositionIndex, intval($pannel['step']));
$options = &$pannels[intval($pannel['step'])]['options'];
$keys = ['frameType', 'color', 'rempl'];
foreach($keys as $key) {
if (array_key_exists($key, $options) && gettype($options[$key]) == "string") {
$options[$key] = $this->getDoctrine()->getRepository(Option::class)->find($options[$key]);
}
}
}
ksort($pannels);
$pdf = new Fpdi();
// Fetch specific theme colors if there is one, otherwise use seed
$profil = $session->get('profil');
$file = sprintf("%s/config/theme/%s.php", $projectDir, $profil);
if(!file_exists($file)) {
$file = sprintf("%s/config/theme/seed.php", $projectDir);
}
$profil = require($file);
foreach($pannels as $pannel) {
$pack = $canopy->handleAjax("getComponents", $pannel);
$dest = sprintf("%s/var/cache/pdf/%s_canopy_%s.pdf", $projectDir, $dayDate, uniqid());
$page = \App\Pdf\Canopy::generate($company->getCompany(), $profil, $pack, $pannel, $disposition,
sprintf(
"%s/public/uploads/%s",
$projectDir,
$company->getCompany()->getLogo()
), $translator
);
if(!file_exists(dirname($dest))) {
mkdir(dirname($dest));
}
// Generate pdf to temporary file and merge it to the main pdf
$page->Output("F", $dest);
$pages = $pdf->setSourceFile($dest);
for($page = 0; $page < $pages; $page++) {
$pdf->AddPage();
$i = $pdf->importPage($page+1);
$pdf->useTemplate($i, 0, 0, 200);
}
unlink($dest);
}
$dest = sprintf("%s/var/cache/pdf/%s_canopy_%s.pdf", $projectDir, $dayDate, uniqid());
if(!file_exists(dirname($dest))) {
mkdir(dirname($dest));
}
$pdf->Output("F", $dest);
$config = Yaml::parseFile($configFile);
$config['pdf'] = $dest;
file_put_contents($configFile, Yaml::dump($config, 4));
return $dest;
}
private function getXML(Canopy $canopy, Session $session, $projectDir, Packages $pathPackage, Company $company, TranslatorInterface $translator): string
{
$token = $session->get('token');
$user = $this->getUser();
$configFile = sprintf("%s/var/tokens/%s.yaml", $projectDir, $token);
$config = Yaml::parseFile($configFile);
$dayDate = (new \DateTime())->format("Y-m-d");
// Remove unnecessary keys
unset($config['time']);
$dispositionIndex = $config['disposition'];
unset($config['disposition']);
unset($config['pdf']);
// Unlink previously created file if there is one
if(array_key_exists("xml", $config)) {
if(file_exists($config['xml'])) {
unlink($config['xml']);
}
unset($config['xml']);
}
$dispositions = $canopy->getDispositions();
$disposition = $dispositions[$dispositionIndex];
$pannels = [];
foreach($config as $pannel) {
$pannels[intval($pannel['step'])] = $pannel;
// Only show prices if activated
if($user->isTarif()) {
$pannels[intval($pannel['step'])]['price'] = $canopy->handleAjax("price", $pannel);
} else {
$pannels[intval($pannel['step'])]['price'] = ['prices' => [], 'price' => null];
}
$pannels[intval($pannel['step'])]['name'] = $canopy->getPanelNameByDisposition($dispositionIndex, intval($pannel['step']));
$options = &$pannels[intval($pannel['step'])]['options'];
$keys = ['frameType', 'color', 'rempl'];
foreach($keys as $key) {
if (array_key_exists($key, $options) && gettype($options[$key]) == "string") {
$options[$key] = $this->getDoctrine()->getRepository(Option::class)->find($options[$key]);
}
}
}
ksort($pannels);
$xmlBuilder = new CanopyXml($company->getCompany(), $pannels, $disposition, $translator, $canopy);
$xmlBuilder->build();
$xml = $xmlBuilder->getXml();
$dest = sprintf("%s/var/cache/xml/%s_canopy_%s.xml", $projectDir, $dayDate, uniqid());
if(!file_exists(dirname($dest))) {
mkdir(dirname($dest));
}
$dom = new \DOMDocument("1.0", "UTF-8");
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
$dom->loadXML($xml);
$xmlFormatted = $dom->saveXML();
$xmlFormatted = mb_convert_encoding($xmlFormatted, 'UTF-8', 'HTML-ENTITIES');
file_put_contents($dest, $xmlFormatted);
$config = Yaml::parseFile($configFile);
$config['xml'] = $dest;
file_put_contents($configFile, Yaml::dump($config, 4));
return $dest;
}
}