Files
2026-09-15 10:35:56 +08:00

171 lines
6.4 KiB
PHP

<?php
declare(strict_types=1);
namespace Esun\ContactPopup\Controller\Index;
use Esun\ContactPopup\Model\Submission;
use Esun\ContactPopup\Model\SubmissionFactory;
use Magento\Contact\Model\ConfigInterface;
use Magento\Contact\Model\MailInterface;
use Magento\Framework\App\Action\HttpPostActionInterface;
use Magento\Framework\App\RequestInterface;
use Magento\Framework\Controller\Result\Json;
use Magento\Framework\Controller\Result\JsonFactory;
use Magento\Framework\DataObject;
use Magento\Framework\Escaper;
use Psr\Log\LoggerInterface;
class Post implements HttpPostActionInterface
{
private const ALLOWED_CATEGORIES = [
'Product',
'Technical support',
'Cooperation',
'Other',
];
public function __construct(
private readonly RequestInterface $request,
private readonly JsonFactory $jsonFactory,
private readonly ConfigInterface $contactsConfig,
private readonly MailInterface $mail,
private readonly SubmissionFactory $submissionFactory,
private readonly Escaper $escaper,
private readonly LoggerInterface $logger
) {
}
public function execute(): Json
{
$result = $this->jsonFactory->create();
try {
$data = $this->validateRequest();
$submission = $this->saveSubmission($data);
} catch (\Magento\Framework\Exception\LocalizedException $exception) {
return $this->errorResult($result, $exception->getMessage(), 422);
} catch (\Throwable $exception) {
$this->logger->critical($exception);
return $this->errorResult($result, __('Unable to save your message. Please try again later.'), 500);
}
$this->sendMail($submission, $data);
return $result->setData([
'success' => true,
'message' => (string)__('Thanks for contacting us. We will respond to you as soon as possible.'),
]);
}
private function validateRequest(): array
{
$company = trim((string)$this->request->getParam('company', ''));
$category = trim((string)$this->request->getParam('question_category', ''));
$name = trim((string)$this->request->getParam('name', ''));
$email = trim((string)$this->request->getParam('email', ''));
$country = trim((string)$this->request->getParam('country', ''));
$details = trim((string)$this->request->getParam('details', ''));
if (trim((string)$this->request->getParam('hideit', '')) !== '') {
throw new \Magento\Framework\Exception\LocalizedException(__('Unable to submit the form.'));
}
if (!in_array($category, self::ALLOWED_CATEGORIES, true)) {
throw new \Magento\Framework\Exception\LocalizedException(__('Select a question category.'));
}
if ($name === '') {
throw new \Magento\Framework\Exception\LocalizedException(__('Enter your name.'));
}
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
throw new \Magento\Framework\Exception\LocalizedException(__('Enter a valid email address.'));
}
if ($country === '') {
throw new \Magento\Framework\Exception\LocalizedException(__('Enter your country.'));
}
if ($details === '') {
throw new \Magento\Framework\Exception\LocalizedException(__('Enter the details.'));
}
if (
mb_strlen($company) > 255 || mb_strlen($name) > 255 ||
mb_strlen($email) > 255 || mb_strlen($country) > 255
) {
throw new \Magento\Framework\Exception\LocalizedException(__('One or more fields are too long.'));
}
if (mb_strlen($details) > 5000) {
throw new \Magento\Framework\Exception\LocalizedException(__('The details must not exceed 5000 characters.'));
}
return compact('company', 'category', 'name', 'email', 'country', 'details');
}
private function saveSubmission(array $data): Submission
{
$submission = $this->submissionFactory->create();
$submission->setData([
'company' => $data['company'],
'question_category' => $data['category'],
'name' => $data['name'],
'email' => $data['email'],
'country' => $data['country'],
'details' => $data['details'],
'mail_status' => 'pending',
]);
$submission->save();
return $submission;
}
private function sendMail(Submission $submission, array $data): void
{
if (!$this->contactsConfig->isEnabled()) {
$submission->setData('mail_status', 'disabled')->save();
return;
}
try {
$this->mail->send($data['email'], ['data' => new DataObject($this->buildMailData($data))]);
$submission->setData('mail_status', 'sent')->setData('mail_error', null)->save();
} catch (\Throwable $exception) {
$this->logger->critical($exception);
try {
$submission->setData('mail_status', 'failed')
->setData('mail_error', mb_substr($exception->getMessage(), 0, 2000))
->save();
} catch (\Throwable $saveException) {
$this->logger->critical($saveException);
}
}
}
private function buildMailData(array $data): array
{
$message = [
$this->mailLine(__('Company Name'), $data['company'] !== '' ? $data['company'] : '-'),
$this->mailLine(__('Question Category'), $data['category']),
$this->mailLine(__('Country'), $data['country']),
'',
$this->escaper->escapeHtml((string)__('Details')) . ':<br>' .
nl2br($this->escaper->escapeHtml($data['details']), false),
];
return [
'name' => $data['name'],
'email' => $data['email'],
'telephone' => '',
'comment' => implode('<br>', $message),
];
}
private function mailLine(\Stringable|string $label, string $value): string
{
return $this->escaper->escapeHtml((string)$label) . ': ' . $this->escaper->escapeHtml($value);
}
private function errorResult(Json $result, \Stringable|string $message, int $statusCode): Json
{
$result->setHttpResponseCode($statusCode);
return $result->setData([
'success' => false,
'message' => (string)$message,
]);
}
}