Files
kupshop/bundles/KupShop/ContentBundle/View/ContactFormView.php
2025-08-02 16:30:27 +02:00

410 lines
12 KiB
PHP

<?php
namespace KupShop\ContentBundle\View;
use KupShop\ComponentsBundle\View\ComponentsViewInterface;
use KupShop\ComponentsBundle\View\ComponentsViewTrait;
use KupShop\ContentBundle\Event\FormEvent;
use KupShop\ContentBundle\Util\Captcha;
use KupShop\ContentBundle\View\Exception\ValidationException;
use KupShop\KupShopBundle\Util\Mail\EmailCheck;
use KupShop\KupShopBundle\Util\StringUtil;
use KupShop\KupShopBundle\Views\Traits\RequestTrait;
use KupShop\KupShopBundle\Views\View;
use KupShop\OrderingBundle\Util\UserContent\UserContent;
use Query\Operator;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class ContactFormView extends View implements ComponentsViewInterface
{
use \DatabaseCommunication;
use RequestTrait;
use ComponentsViewTrait;
protected $formData = [];
protected $emailSent = false;
/** @var string Name of form to use - defined in config.modules.forms */
protected $formType = 'kontakt';
private $formConfig;
/**
* @var SessionInterface
*/
private $session;
/**
* @var EmailCheck
*/
private $emailCheck;
/**
* @var string Backward Compatibility for form templates without user messages
*/
protected $error;
/**
* @var bool Use.error for reporting error to template
*/
protected $compatibilityMode = false;
private $dispatcher;
protected UserContent $userContent;
public function __construct(SessionInterface $session, EventDispatcherInterface $dispatcher, EmailCheck $emailCheck, UserContent $userContent)
{
$this->session = $session;
$this->dispatcher = $dispatcher;
$this->emailCheck = $emailCheck;
$this->userContent = $userContent;
}
public function getConfig()
{
if (is_null($this->formConfig)) {
$config = $this->getDefaultConfig();
$this->formConfig = array_merge($config, $this->getCustomConfig());
}
return $this->formConfig;
}
public function getDefaultConfig()
{
$dbCfg = \Settings::getDefault();
return [
'title' => 'Kontaktní formulář',
'template' => 'form/contact.tpl',
'subject' => 'email/contact_subject.tpl',
'message' => 'email/contact_message.tpl',
'message_answer' => null,
'subject_answer' => null,
'email' => $dbCfg->order_shopkeeper_mail,
'required' => [
'email' => 'Email',
],
];
}
public function getCustomConfig()
{
$config = [];
if ($this->formType == 'dotaz-na-produkt') {
$config = [
'title' => 'Dotaz na produkt',
'template' => 'form/product_question.tpl',
'subject' => 'email/product_question_subject.tpl',
'message' => 'email/product_question.tpl',
'required' => [
'email' => 'Email',
'message' => 'Dotaz',
],
];
}
if ($this->formType == 'report-inappropriate-content') {
$config = [
'title' => 'Nahlásit závadný obsah',
'template' => 'form/report-inappropriate-content.tpl',
'subject' => 'email/report-inappropriate-content_subject.tpl',
'message' => 'email/report-inappropriate-content.tpl',
'message_answer' => 'email/report-inappropriate-content_answer.tpl',
'subject_answer' => 'email/report-inappropriate-content_subject_answer.tpl',
'required' => [
'reason' => 'Důvod',
],
];
}
$form = findModule('forms', $this->formType, []);
// TODO: Odstranit tohle az bude findModule skutecne vzdy vracet fallback
if (!is_array($form)) {
$form = [];
}
$config = array_merge($config, $form);
$translate_config = translate($this->formType, 'forms', true);
if (is_array($translate_config)) {
$config = array_merge($config, $translate_config);
}
return $config;
}
protected function getEmails()
{
$from = getVal('email', $this->getFormData());
$send_to = getVal('send_to', $this->getFormData());
$bcc = getVal('bcc', $this->getFormData());
if (!$from) {
throw new \Exception('ContactFormView: Undefined source email address');
}
if (is_callable($this->getConfig()['email'])) {
$email = $this->getConfig()['email']();
} else {
$email = $this->getConfig()['email'];
}
return [
'from' => $from,
'to' => ($send_to) ? $send_to : $email,
'bcc' => ($bcc) ? [$bcc] : (isset($this->getConfig()['bcc']) ? [$this->getConfig()['bcc']] : []),
];
}
public function getTitle()
{
return $this->getConfig()['title'];
}
/**
* @param array $errors
*
* @return int
*
* @throws ValidationException
*/
public function validate($data, $form, &$errors = [])
{
// Check required fields
$required = getVal('required', $form, []);
foreach ($required as $field => $display) {
if (empty($data[$field])) {
$errors[] = $display;
}
}
if (!empty($errors)) {
throw new ValidationException(translate('errorRequiredMissing', 'form').join(', ', $errors));
}
// Logged users does not require CAPTCHA validation
if (!\User::getCurrentUser()) {
Captcha::checkCaptcha($data);
}
$emails = $this->getEmails();
$emailsValidate = array_map(function ($email) { return StringUtil::unicode_trim($email); },
array_merge([$emails['from']],
explode(',', $emails['to']),
$emails['bcc']));
foreach ($emailsValidate as $email) {
if (!empty($email) && !$this->emailCheck->isEmailDomainValid($email)) {
throw new ValidationException(translate('errorInvalidEmail', 'form').htmlentities($email));
}
}
$this->dispatcher->dispatch(new FormEvent($this->formType, $data, $form), FormEvent::FORM_VALIDATE);
return 0;
}
protected function getAttachments()
{
$attachments = [];
foreach ($_FILES as $file) {
if (is_array($file['name'])) {
foreach ($file['name'] as $index => $name) {
if (!empty($name)) {
$attachments[] = ['path' => $file['tmp_name'][$index], 'filename' => $name];
}
}
} else {
if (!empty($file['tmp_name'])) {
$attachments[] = ['path' => $file['tmp_name'], 'filename' => $file['name']];
}
}
}
return $attachments;
}
protected function saveUser($from)
{
$form_fields = [
'figure' => 'N',
];
$confirmed = false;
if (!empty($this->formData['get_news']) && $this->formData['get_news'] == 'force') {
$this->formData['get_news'] = 'Y';
$confirmed = true;
}
$user_fields = [
'name', 'surname', 'phone', 'firm', 'ico', 'dic', 'street', 'city', 'zip', 'country',
'delivery_name', 'delivery_surname', 'delivery_firm', 'delivery_street', 'delivery_city', 'delivery_zip', 'delivery_country',
'get_news', 'custom_data', 'copy_email',
];
foreach ($user_fields as $field) {
$value = getVal($field, $this->formData);
if (!empty($value)) {
$form_fields[$field] = $value;
}
}
if (!empty($form_fields['custom_data'])) {
$form_fields['custom_data'] = json_encode($form_fields['custom_data']);
}
if (($form_fields['get_news'] ?? null) == 'Y' && $this->selectSQL('users', ['email' => $from, 'figure' => 'N'])->fetch()) {
$values = $form_fields;
unset($values['get_news']);
sqlQueryBuilder()->update('users')->directValues($values)->where(Operator::equals(['email' => $from]))->execute();
}
addUserEmail($from, [$this->getConfig()['title']], $form_fields, $confirmed);
}
public function getBodyVariables()
{
return [
'error' => $this->error,
'data' => $this->getFormData(),
'form' => $this->getConfig(),
'sent' => $this->emailSent,
] + parent::getBodyVariables();
}
private function sendEmail()
{
$config = $this->getConfig();
$smarty = $this->getSmarty();
$emails = $this->getEmails();
$get_news = getVal('get_news', $this->formData, 'N');
if ($get_news == 'Y' || $get_news == 'force') {
$this->saveUser($emails['from']);
}
$smarty->assign($this->getTemplateVariables());
$subject = trim($smarty->fetch($config['subject']));
$message = $smarty->fetch($config['message']);
$attachments = $this->getAttachments();
SendMail($emails['from'], $emails['to'], $subject, $message, 'text/html', $attachments, null, $emails['bcc']);
if (!empty($config['message_answer'])) {
$subject = $smarty->fetch($config['subject_answer']);
$message = $smarty->fetch($config['message_answer']);
SendMail($emails['to'], $emails['from'], $subject, $message, 'text/html');
}
$this->session->set('product_question', [
'email' => getVal('from', $emails),
'firstname' => getVal('name', $this->formData),
]);
}
public function submitForm()
{
$data = $this->getFormData();
$config = $this->getConfig();
try {
$this->validate($data, $config, $errorFields);
} catch (ValidationException $e) {
if ($this->compatibilityMode) {
$this->error = $e->getMessage();
} else {
$this->addErrorMessage($e->getMessage());
}
return false;
}
$this->dispatcher->dispatch(new FormEvent($this->formType, $data, $config), FormEvent::FORM_SUBMITTED);
$this->sendEmail();
// Mazání nahraných souborů přes uploader. Snad to nebude vadit nějakýmu emailu, že o ty data příjde moc brzy
// Případně se to uloží do session k form data
if ($data['user_content'] ?? false) {
$this->userContent->clearData($data['user_content']);
}
return true;
}
private function getFormData()
{
if ($this->emailSent) {
return $this->session->get("form-{$this->formType}");
}
return $this->formData;
}
public function getTemplate(): string
{
return $this->getConfig()['template'];
}
public function getShowInSearch(): bool
{
return empty($_GET) && empty($_POST);
}
/**
* @return ContactFormView
*/
public function setFormData($formData)
{
$this->formData = $formData;
if (!$this->emailSent) {
$this->session->set("form-{$this->formType}", $formData);
}
return $this;
}
/**
* @return ContactFormView
*/
public function setFormType($formType)
{
$this->formType = $formType;
if (!$this->getSmarty()->templateExists($this->getConfig()['template'])) {
throw new NotFoundHttpException('Form not found');
}
return $this;
}
/**
* @param bool $emailSent
*
* @return ContactFormView
*/
public function setEmailSent($emailSent)
{
$this->emailSent = $emailSent;
return $this;
}
public function setCompatibilityMode(bool $compatibilityMode): ContactFormView
{
$this->compatibilityMode = $compatibilityMode;
return $this;
}
}