Spaces:
No application file
No application file
| declare(strict_types=1); | |
| namespace Mautic\LeadBundle\Model; | |
| use Doctrine\ORM\EntityManager; | |
| use Mautic\CoreBundle\Helper\CoreParametersHelper; | |
| use Mautic\CoreBundle\Helper\ExportHelper; | |
| use Mautic\CoreBundle\Helper\UserHelper; | |
| use Mautic\CoreBundle\Model\AbstractCommonModel; | |
| use Mautic\CoreBundle\Model\IteratorExportDataModel; | |
| use Mautic\CoreBundle\Security\Permissions\CorePermissions; | |
| use Mautic\CoreBundle\Translation\Translator; | |
| use Mautic\EmailBundle\Helper\MailHelper; | |
| use Mautic\LeadBundle\Entity\ContactExportScheduler; | |
| use Mautic\LeadBundle\Entity\ContactExportSchedulerRepository; | |
| use Mautic\UserBundle\Entity\User; | |
| use Psr\Log\LoggerInterface; | |
| use Symfony\Component\EventDispatcher\EventDispatcherInterface; | |
| use Symfony\Component\HttpFoundation\BinaryFileResponse; | |
| use Symfony\Component\HttpFoundation\Request; | |
| use Symfony\Component\HttpFoundation\RequestStack; | |
| use Symfony\Component\HttpFoundation\Response; | |
| use Symfony\Component\HttpFoundation\Session\SessionInterface; | |
| use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; | |
| use Symfony\Component\Routing\Generator\UrlGeneratorInterface; | |
| /** | |
| * @extends AbstractCommonModel<ContactExportScheduler> | |
| */ | |
| class ContactExportSchedulerModel extends AbstractCommonModel | |
| { | |
| private const EXPORT_FILE_NAME_DATE_FORMAT = 'Y_m_d_H_i_s'; | |
| public function __construct( | |
| private SessionInterface $session, | |
| private RequestStack $requestStack, | |
| private LeadModel $leadModel, | |
| private ExportHelper $exportHelper, | |
| private MailHelper $mailHelper, | |
| EntityManager $em, | |
| CorePermissions $security, | |
| EventDispatcherInterface $dispatcher, | |
| UrlGeneratorInterface $router, | |
| Translator $translator, | |
| UserHelper $userHelper, | |
| LoggerInterface $mauticLogger, | |
| CoreParametersHelper $coreParametersHelper | |
| ) { | |
| parent::__construct($em, $security, $dispatcher, $router, $translator, $userHelper, $mauticLogger, $coreParametersHelper); | |
| } | |
| public function getRepository(): ContactExportSchedulerRepository | |
| { | |
| /** @var ContactExportSchedulerRepository $repo */ | |
| $repo = $this->em->getRepository(ContactExportScheduler::class); | |
| return $repo; | |
| } | |
| /** | |
| * @param array<mixed> $permissions | |
| * | |
| * @return array<string, mixed> | |
| */ | |
| public function prepareData(array $permissions): array | |
| { | |
| $search = $this->session->get('mautic.lead.filter', ''); | |
| $orderBy = $this->session->get('mautic.lead.orderby', 'l.last_active'); | |
| $orderByDir = $this->session->get('mautic.lead.orderbydir', 'DESC'); | |
| $indexMode = $this->session->get('mautic.lead.indexmode', 'list'); | |
| $anonymous = $this->translator->trans('mautic.lead.lead.searchcommand.isanonymous'); | |
| /** @var Request $request */ | |
| $request = $this->getRequest(); | |
| $ids = $request->get('ids'); | |
| $fileType = $request->get('filetype', 'csv'); | |
| $filter = ['string' => $search, 'force' => []]; | |
| if (!empty($ids)) { | |
| $filter['force'] = [ | |
| [ | |
| 'column' => 'l.id', | |
| 'expr' => 'in', | |
| 'value' => json_decode($ids, true, 512, JSON_THROW_ON_ERROR), | |
| ], | |
| ]; | |
| } else { | |
| if ('list' !== $indexMode || (!str_contains($search, $anonymous))) { | |
| // Remove anonymous leads unless requested to prevent clutter. | |
| $filter['force'] = [ | |
| [ | |
| 'column' => 'l.dateIdentified', | |
| 'expr' => 'isNotNull', | |
| ], | |
| ]; | |
| } | |
| if (!$permissions['lead:leads:viewother']) { | |
| // Show only owner's contacts. | |
| $filter['force'] = [ | |
| [ | |
| 'column' => 'l.owner', | |
| 'expr' => 'eq', | |
| ], | |
| ]; | |
| } | |
| } | |
| return [ | |
| 'start' => 0, | |
| 'limit' => $this->coreParametersHelper->get('contact_export_batch_size', 1000), | |
| 'filter' => $filter, | |
| 'orderBy' => $orderBy, | |
| 'orderByDir' => $orderByDir, | |
| 'withTotalCount' => true, | |
| 'fileType' => $fileType, | |
| ]; | |
| } | |
| /** | |
| * @param array<mixed> $data | |
| */ | |
| public function saveEntity(array $data): ContactExportScheduler | |
| { | |
| $contactExportScheduler = new ContactExportScheduler(); | |
| $contactExportScheduler | |
| ->setUser($this->userHelper->getUser()) | |
| ->setScheduledDateTime(new \DateTimeImmutable()) | |
| ->setData($data); | |
| $this->em->persist($contactExportScheduler); | |
| $this->em->flush(); | |
| return $contactExportScheduler; | |
| } | |
| public function processAndGetExportFilePath(ContactExportScheduler $contactExportScheduler): string | |
| { | |
| $data = $contactExportScheduler->getData(); | |
| $fileType = $data['fileType']; | |
| $resultsCallback = fn ($contact) => $contact->getProfileFields(); | |
| $iterator = new IteratorExportDataModel( | |
| $this->leadModel, | |
| $contactExportScheduler->getData(), | |
| $resultsCallback, | |
| true | |
| ); | |
| /** @var \DateTimeImmutable $scheduledDateTime */ | |
| $scheduledDateTime = $contactExportScheduler->getScheduledDateTime(); | |
| $fileName = 'contacts_export_'.$scheduledDateTime->format(self::EXPORT_FILE_NAME_DATE_FORMAT); | |
| return $this->exportResultsAs($iterator, $fileType, $fileName); | |
| } | |
| public function getEmailMessageWithLink(string $filePath): string | |
| { | |
| $link = $this->router->generate( | |
| 'mautic_contact_export_download', | |
| ['fileName' => basename($filePath)], | |
| UrlGeneratorInterface::ABSOLUTE_URL | |
| ); | |
| return $this->translator->trans( | |
| 'mautic.lead.export.email', | |
| ['%link%' => $link, '%label%' => basename($filePath)] | |
| ); | |
| } | |
| public function sendEmail(ContactExportScheduler $contactExportScheduler, string $filePath): void | |
| { | |
| /** @var User $user */ | |
| $user = $contactExportScheduler->getUser(); | |
| $message = $this->getEmailMessageWithLink($filePath); | |
| $this->mailHelper->setTo([$user->getEmail() => $user->getName()]); | |
| $this->mailHelper->setSubject( | |
| $this->translator->trans('mautic.lead.export.email_subject', ['%file_name%' => basename($filePath)]) | |
| ); | |
| $this->mailHelper->setBody($message); | |
| $this->mailHelper->parsePlainText($message); | |
| $this->mailHelper->send(true); | |
| } | |
| public function deleteEntity(ContactExportScheduler $contactExportScheduler): void | |
| { | |
| $this->em->remove($contactExportScheduler); | |
| $this->em->flush(); | |
| } | |
| public function getExportFileToDownload(string $fileName): BinaryFileResponse | |
| { | |
| $filePath = $this->coreParametersHelper->get('contact_export_dir').'/'.$fileName; | |
| $contentType = $this->getContactExportFileContentType($fileName); | |
| return new BinaryFileResponse( | |
| $filePath, | |
| Response::HTTP_OK, | |
| [ | |
| 'Content-Type' => $contentType, | |
| 'Content-Disposition' => 'attachment; filename="'.$fileName.'"', | |
| 'Expires' => 0, | |
| 'Cache-Control' => 'must-revalidate', | |
| 'Pragma' => 'public', | |
| ] | |
| ); | |
| } | |
| private function getRequest(): ?Request | |
| { | |
| return $this->requestStack->getCurrentRequest(); | |
| } | |
| private function exportResultsAs(IteratorExportDataModel $iterator, string $fileType, string $fileName): string | |
| { | |
| if (!in_array($fileType, $this->exportHelper->getSupportedExportTypes(), true)) { | |
| throw new BadRequestHttpException($this->translator->trans('mautic.error.invalid.export.type', ['%type%' => $fileType])); | |
| } | |
| $csvFilePath = $this->exportHelper | |
| ->exportDataIntoFile($iterator, $fileType, strtolower($fileName.'.'.$fileType)); | |
| return $this->exportHelper->zipFile($csvFilePath, 'contacts_export.csv'); | |
| } | |
| private function getContactExportFileContentType(string $fileName): string | |
| { | |
| $ext = pathinfo($fileName, PATHINFO_EXTENSION); | |
| if ('zip' === $ext) { | |
| return 'application/zip'; | |
| } | |
| throw new BadRequestHttpException($this->translator->trans('mautic.error.invalid.specific.export.type', ['%type%' => $ext, '%expected_type%' => 'zip'])); | |
| } | |
| } | |