<?php
/**
* Created by Elements.at New Media Solutions GmbH
*
*/
namespace App\Controller;
use App\Templating\Helper\LinkGenerator;
use App\Twig\ConfigHelper;
use App\Twig\SimpleHelper;
use Carbon\Carbon;
use Elements\Bundle\CmsToolsBundle\Tool\Helper\MailHelper;
use Elements\Bundle\HashCashBundle\Service\HashCashService;
use Pimcore\Bundle\AdminBundle\HttpFoundation\JsonResponse;
use Pimcore\Mail;
use Pimcore\Model\DataObject\CompleteConfiguration;
use Pimcore\Model\DataObject\ConfigurationComponent;
use Pimcore\Model\DataObject\ConfigurationProduct;
use Pimcore\Model\DataObject\Service;
use Pimcore\Model\DataObject\SiteConfig;
use Pimcore\Model\Document\Email;
use Pimcore\Model\Document\Page;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class ConfiguratorController extends AbstractController
{
public function __construct(private readonly LinkGenerator $linkGenerator, private readonly ConfigHelper $configHelper, private readonly HashCashService $hashCashService)
{
}
/**
*
* @param Request $request
*
* @return Response
*/
public function overviewAction(Request $request): Response
{
$returnArray = [];
$configuratorObjects = new ConfigurationProduct\Listing();
if ($request->get('ajaxForm')) {
$siteConfig = $this->configHelper->getSiteConfig();
if ($siteConfig instanceof SiteConfig && $siteConfig->getSuccessPageConfigurator() && $siteConfig->getAdminMailConfigurator() && $siteConfig->getUserMailConfigurator()) {
$adminMail = $siteConfig->getAdminMailConfigurator();
$userMail = $siteConfig->getUserMailConfigurator();
$successPage = $siteConfig->getSuccessPageConfigurator();
}
$required = ['name', 'company', 'mail', 'street', 'zip', 'city'];
$params = $this->checkForm($request, $required);
if (!empty($params['errors'])) {
$errors[] = $params['errors'];
} else {
$adminMailSuccess = false;
$userMailSuccess = false;
if (isset($adminMail) && $adminMail instanceof Email) {
$mail = new Mail();
try {
$mail->setParams($params);
$mail->setDocument($adminMail);
$mail->send();
$adminMailSuccess = true;
} catch(\Throwable $t) {
$errors[] = 'sending admin mail failed: ' . $t->getMessage();
}
}
if (isset($userMail) && $userMail instanceof Email) {
$mail = new Mail();
try {
$mail->addTo($params['mail']);
$mail->setDocument($userMail);
$mail->send();
$userMailSuccess = true;
} catch(\Throwable $t) {
$errors[] = 'sending user mail failed: ' . $t->getMessage();
}
}
if (empty($errors) && $adminMailSuccess && $userMailSuccess && isset($successPage) && $successPage instanceof Page) {
return $this->redirect((string)$successPage);
}
}
return $this->json([
'success' => false,
'errors' => $errors ?? [],
]);
}
if ($request->isXmlHttpRequest() && $request->get('ajax')) {
$completeConfigurations = new CompleteConfiguration\Listing();
$completeConfigurations->addConditionParam('code = ?', [$request->get('search')]);
$completeConfiguration = $completeConfigurations->current();
if ($completeConfiguration instanceof CompleteConfiguration) {
return $this->json([
'success' => true,
'html' =>$this->redirect($this->linkGenerator->generate($completeConfiguration), 301)->getContent(),
]);
}
}
$returnArray['configurationProducts'] = $configuratorObjects->load();
return $this->renderTemplate('configurator/overview.html.twig', $returnArray);
}
/**
*
* @param Request $request
*
* @return Response
*/
public function detailAction(Request $request, ConfigurationProduct $id): Response
{
$configuration = $id;
$steps = [];
$componentData = [];
foreach ($configuration->getConfigItems() as $configItem) {
$steps[$configItem->getStep()] = [
'step' => $configItem->getStep(),
'name' => $configItem->getVariantType(),
'mandatory' => $configItem->getIsMandatory(),
];
}
$steps = array_values($steps);
foreach ($configuration->getConfigItems() as $configItem) {
$mandatoryComponentIds = [];
foreach ($configItem->getMandatoryComponents() as $mandComponent) {
$mandatoryComponentIds[] = $mandComponent->getId();
}
$incompatibleComponents = [];
foreach ($configItem->getIncompatibleComponents() as $incompatibleComponent) {
$incompatibleComponents[] = $incompatibleComponent->getId();
}
$componentData[] = [
"pimcoreId" => $configItem->getId(),
"title" => strip_tags($configItem->getDescription()),
"description" => strip_tags($configItem->getDescription()),
"shortDescription" => $configItem->getArticleNumber(),
"price" => intval($configItem->getPrice()),
"mandatoryComponents" => $mandatoryComponentIds,
"incompatibleComponents" => $incompatibleComponents,
"categoryStep" => $configItem->getStep(),
"defaultSelected" => $configItem->getIsDefault(),
];
}
$configurationToEdit = [];
if ($request->get('completeConfigurationId')) {
$completeConfiguration = CompleteConfiguration::getById($request->get('completeConfigurationId'));
if ($completeConfiguration instanceof CompleteConfiguration) {
$parts = [];
foreach ($completeConfiguration->getParts() as $part) {
$parts[] = $part->getId();
}
$configurationToEdit = [
'componentsById' => $parts,
'configurationName' => $completeConfiguration->getTitle(),
'code' => $completeConfiguration->getCode(),
];
}
}
$returnArray = [
'steps' => $steps,
'configuration' => $configuration,
'componentData' => $componentData,
'configurationToEdit' => $configurationToEdit,
];
return $this->renderTemplate('configurator/detail.html.twig', $returnArray);
}
/**
* @param Request $request
*
* @return JsonResponse
*/
#[Route('/{_locale}/vue/configurator-save-json', name: 'vue_configurator-save-json')]
public function configuratorSaveJsonAction(Request $request)
{
$this->addResponseHeader('X-Robots-Tag', 'noindex', true);
if ($request->get('productId')) {
$configuration = ConfigurationProduct::getById($request->get('productId'));
$components = json_decode($request->get('components'), true);
$configurationName = $request->get('configurationName');
$productId = $request->get('productId');
$code = $request->get('code');
$price = $request->get('price');
$completeConfiguration = $this->getOrCreateCompleteConfiguration($configuration, $components, $code, $configurationName, $productId, $price);
$detailLink = $this->linkGenerator->generate($completeConfiguration, ['id' => $completeConfiguration->getCode()]);
$responseData = [
'success' => true,
'detailLink' => $detailLink,
'configurationId' => $completeConfiguration->getCode(),
];
} else {
$responseData = [
'success' => false,
];
}
return new JsonResponse($responseData);
}
/**
* @param Request $request
*
* @return Response
*
* if pdf is last word of route, nginx looks for a file in /public.
* took me way too long to figure that out - now its pdf-print
*/
#[Route('/{_locale}/vue/configurator-pdf-print', name: 'vue_configurator-print-pdf')]
public function configuratorPrintPdfAction(Request $request): Response
{
$completeConfiguration = CompleteConfiguration::getById($request->query->get('completeConfiguration'));
$html = $this->renderTemplate('configurator/pdf/result-pdf.html.twig', ['completeConfiguration' => $completeConfiguration])->getContent();
$adapter = \Pimcore\Web2Print\Processor::getInstance();
$params = [
'filename' => 'configurator-' . $completeConfiguration->getCode() . '.pdf',
'landscape' => false,
'printBackground' => true,
'displayHeaderFooter' => true,
'format' => 'A4',
'margin' => [
'top' => '35 mm',
'bottom' => '40 mm',
'right' => '14.11 mm',
'left' => '14.11 mm',
],
'headerTemplate' => $this->getHeaderTemplate(),
'footerTemplate' => $this->getFooterTemplate()
];
return new \Symfony\Component\HttpFoundation\Response(
$adapter->getPdfFromString($html, $params),
200,
array(
'Content-Type' => 'application/pdf',
)
);
}
private function getHeaderTemplate(): string {
return $this->renderTemplate('configurator/pdf/result-pdf-header.html.twig')->getContent();
}
private function getFooterTemplate(): string {
return $this->renderTemplate('configurator/pdf/result-pdf-footer.html.twig')->getContent();
}
/**
*
* @param Request $request
*
* @return Response
*/
public function resultAction(Request $request, CompleteConfiguration $code): Response
{
if ($request->isXmlHttpRequest() && $request->get('ajax')) {
$returnArray = [
'completeConfiguration' => $code,
];
}
$returnArray = [
'completeConfiguration' => $code,
];
return $this->renderTemplate('configurator/partials/result.html.twig', $returnArray);
}
private function generateUniqueCode(int $objectId): string
{
$length = 6;
$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
$code = $objectId % 100000;
for ($i = 0; $i <= $length - strlen($code); $i++) {
$code .= $chars[random_int(0, strlen($chars) - 1)];
}
return $code;
}
private function getOrCreateCompleteConfiguration(ConfigurationProduct $configuration, mixed $components, string|null $code, string $configurationName, int $productId, string $price): ?CompleteConfiguration
{
$completeConfiguration = CompleteConfiguration::getByCode($code);
$completeConfiguration = $completeConfiguration->current();
if (!$completeConfiguration instanceof CompleteConfiguration) {
\Pimcore\Model\Version::disable();
$completeConfiguration = new CompleteConfiguration();
$completeConfiguration->setPublished(false);
$completeConfiguration->setParent(Service::createFolderByPath('Configurator/CompleteConfigurations'));
$objectKey = Service::getValidKey(Carbon::now()->timestamp, 'object');
$completeConfiguration->setKey($objectKey);
try {
$completeConfiguration->save();
} catch (\Exception $exception) {
p_r(SimpleHelper::printException($exception));
}
$code = $this->generateUniqueCode($completeConfiguration->getId());
$completeConfiguration->setCode($code);
$objectKey = Service::getValidKey($configuration->getModell() . '-' . $code, 'object');
$completeConfiguration->setKey($objectKey);
try {
$completeConfiguration->setPublished(true);
$completeConfiguration->save();
} catch (\Throwable $exception) {
p_r(SimpleHelper::printException($exception));
return null;
}
}
$componentObjects = [];
foreach ($components as $componentId) {
$componentObjects[] = ConfigurationComponent::getById($componentId);
}
$completeConfiguration->setParts($componentObjects);
$completeConfiguration->setConfigurationProduct($configuration);
$completeConfiguration->setTitle($configurationName);
$completeConfiguration->setPrice($price);
try {
$completeConfiguration->save();
} catch (\Throwable $exception) {
p_r(SimpleHelper::printException($exception));
return null;
}
return $completeConfiguration;
}
private function checkForm(Request $request, mixed $required): mixed
{
$validHashCash = $this->hashCashService->validateProcessFrom();
if ($validHashCash) {
$params = $request->request->all();
unset($params['elhc_stamp'], $params['elhc_difficulty'], $params['elhc_nonce']);
$errors = [];
foreach ($required as $param) {
if ($request->get($param) == '') {
$errors[$param] = $param . ' is missing';
}
if ($param == 'mail' && !MailHelper::isValidEmailAddress($request->get($param))) {
$errors[$param] = 'mail invalid';
}
}
if (!empty($errors)) {
$params['errors'] = $errors;
}
$params['items'] = $params;
} else {
$params['errors'] = ['recaptcha' => 'invalid captcha'];
}
return $params;
}
}