Current File : //var/www/vinorea/src/PrestaShopBundle/Controller/Admin/Improve/Design/MailThemeController.php
<?php
/**
 * Copyright since 2007 PrestaShop SA and Contributors
 * PrestaShop is an International Registered Trademark & Property of PrestaShop SA
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Open Software License (OSL 3.0)
 * that is bundled with this package in the file LICENSE.md.
 * It is also available through the world-wide-web at this URL:
 * https://opensource.org/licenses/OSL-3.0
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@prestashop.com so we can send you a copy immediately.
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade PrestaShop to newer
 * versions in the future. If you wish to customize PrestaShop for your
 * needs please refer to https://devdocs.prestashop.com/ for more information.
 *
 * @author    PrestaShop SA and Contributors <contact@prestashop.com>
 * @copyright Since 2007 PrestaShop SA and Contributors
 * @license   https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
 */

namespace PrestaShopBundle\Controller\Admin\Improve\Design;

use Mail;
use PrestaShop\PrestaShop\Adapter\MailTemplate\MailPreviewVariablesBuilder;
use PrestaShop\PrestaShop\Core\Domain\MailTemplate\Command\GenerateThemeMailTemplatesCommand;
use PrestaShop\PrestaShop\Core\Employee\ContextEmployeeProviderInterface;
use PrestaShop\PrestaShop\Core\Exception\CoreException;
use PrestaShop\PrestaShop\Core\Exception\FileNotFoundException;
use PrestaShop\PrestaShop\Core\Exception\InvalidArgumentException;
use PrestaShop\PrestaShop\Core\Form\FormHandlerInterface;
use PrestaShop\PrestaShop\Core\Language\LanguageRepositoryInterface;
use PrestaShop\PrestaShop\Core\MailTemplate\Layout\LayoutInterface;
use PrestaShop\PrestaShop\Core\MailTemplate\MailTemplateInterface;
use PrestaShop\PrestaShop\Core\MailTemplate\MailTemplateRendererInterface;
use PrestaShop\PrestaShop\Core\MailTemplate\ThemeCatalogInterface;
use PrestaShop\PrestaShop\Core\MailTemplate\ThemeInterface;
use PrestaShop\PrestaShop\Core\MailTemplate\Transformation\MailVariablesTransformation;
use PrestaShopBundle\Controller\Admin\FrameworkBundleAdminController;
use PrestaShopBundle\Form\Admin\Improve\Design\MailTheme\GenerateMailsType;
use PrestaShopBundle\Form\Admin\Improve\Design\MailTheme\TranslateMailsBodyType;
use PrestaShopBundle\Security\Annotation\AdminSecurity;
use PrestaShopBundle\Service\TranslationService;
use Symfony\Component\Form\Form;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

/**
 * Class MailThemeController manages mail theme generation, you can define the shop
 * mail theme, and regenerate mail in a specific language.
 *
 * Accessible via "Design > Mail Theme"
 */
class MailThemeController extends FrameworkBundleAdminController
{
    /**
     * Show mail theme settings and generation page.
     *
     * @AdminSecurity("is_granted('read', request.get('_legacy_controller'))")
     *
     * @param Request $request
     *
     * @return Response
     */
    public function indexAction(Request $request)
    {
        $legacyController = $request->attributes->get('_legacy_controller');
        $generateThemeMailsForm = $this->createForm(GenerateMailsType::class);
        $translateMailsBodyForm = $this->createForm(TranslateMailsBodyType::class);
        /** @var ThemeCatalogInterface $themeCatalog */
        $themeCatalog = $this->get('prestashop.core.mail_template.theme_catalog');
        $mailThemes = $themeCatalog->listThemes();

        return $this->render('@PrestaShop/Admin/Improve/Design/MailTheme/index.html.twig', [
            'layoutHeaderToolbarBtn' => [],
            'layoutTitle' => $this->trans('Email Theme', 'Admin.Navigation.Menu'),
            'enableSidebar' => true,
            'help_link' => $this->generateSidebarLink($legacyController),
            'mailThemeConfigurationForm' => $this->getMailThemeFormHandler()->getForm()->createView(),
            'generateMailsForm' => $generateThemeMailsForm->createView(),
            'translateMailsBodyForm' => $translateMailsBodyForm->createView(),
            'mailThemes' => $mailThemes,
        ]);
    }

    /**
     * Manage generation form post and generate mails.
     *
     * @AdminSecurity("is_granted('create', request.get('_legacy_controller'))")
     *
     * @param Request $request
     *
     * @return Response
     */
    public function generateMailsAction(Request $request)
    {
        $generateThemeMailsForm = $this->createForm(GenerateMailsType::class);
        $generateThemeMailsForm->handleRequest($request);

        if ($generateThemeMailsForm->isSubmitted()) {
            if (!$generateThemeMailsForm->isValid()) {
                $this->flashErrors($this->getFormErrorsForJS($generateThemeMailsForm));

                return $this->redirectToRoute('admin_mail_theme_index');
            }

            $data = $generateThemeMailsForm->getData();
            try {
                $coreMailsFolder = '';
                $modulesMailFolder = '';
                //Overwrite theme folder if selected
                if (!empty($data['theme'])) {
                    if (is_dir($data['theme'] . '/mails')) {
                        $coreMailsFolder = $data['theme'] . '/mails';
                    }
                    if (is_dir($data['theme'] . '/modules')) {
                        $modulesMailFolder = $data['theme'] . '/modules';
                    }
                }

                $generateCommand = new GenerateThemeMailTemplatesCommand(
                    $data['mailTheme'],
                    $data['language'],
                    $data['overwrite'],
                    $coreMailsFolder,
                    $modulesMailFolder
                );

                $commandBus = $this->getCommandBus();
                $commandBus->handle($generateCommand);

                if ($data['overwrite']) {
                    $this->addFlash(
                        'success',
                        $this->trans(
                            'Successfully overwrote email templates for theme %s with locale %s',
                            'Admin.Notifications.Success',
                            [
                                $data['mailTheme'],
                                $data['language'],
                            ]
                        )
                    );
                } else {
                    $this->addFlash(
                        'success',
                        $this->trans(
                            'Successfully generated email templates for theme %s with locale %s',
                            'Admin.Notifications.Success',
                            [
                                $data['mailTheme'],
                                $data['language'],
                            ]
                        )
                    );
                }
            } catch (CoreException $e) {
                $this->flashErrors([
                    $this->trans(
                        sprintf(
                            'Cannot generate email templates for theme %s with locale %s',
                            $data['mailTheme'],
                            $data['language']
                        ),
                        'Admin.Notifications.Error'
                    ),
                    $e->getMessage(),
                ]);
            }
        }

        return $this->redirectToRoute('admin_mail_theme_index');
    }

    /**
     * Save mail theme configuration
     *
     * @AdminSecurity("is_granted('update', request.get('_legacy_controller'))")
     *
     * @param Request $request
     *
     * @return Response
     *
     * @throws \Exception
     */
    public function saveConfigurationAction(Request $request)
    {
        /** @var FormHandlerInterface $formHandler */
        $formHandler = $this->getMailThemeFormHandler();
        /** @var Form $form */
        $form = $formHandler->getForm()->handleRequest($request);

        if ($form->isSubmitted()) {
            if (!$form->isValid()) {
                $this->flashErrors($this->getFormErrorsForJS($form));

                return $this->redirectToRoute('admin_mail_theme_index');
            }

            $errors = $formHandler->save($form->getData());
            if (empty($errors)) {
                $this->addFlash(
                    'success',
                    $this->trans(
                        'Email theme configuration saved successfully',
                        'Admin.Notifications.Success'
                    )
                );
            } else {
                $this->flashErrors($errors);
            }
        }

        return $this->redirectToRoute('admin_mail_theme_index');
    }

    /**
     * Preview the list of layouts for a defined theme
     *
     * @AdminSecurity("is_granted('read', request.get('_legacy_controller'))")
     *
     * @param Request $request
     * @param string $theme
     *
     * @return Response
     *
     * @throws InvalidArgumentException
     */
    public function previewThemeAction(Request $request, $theme)
    {
        $legacyController = $request->attributes->get('_legacy_controller');

        /** @var ThemeCatalogInterface $themeCatalog */
        $themeCatalog = $this->get('prestashop.core.mail_template.theme_catalog');
        /** @var ThemeInterface $mailTheme */
        $mailTheme = $themeCatalog->getByName($theme);

        return $this->render('@PrestaShop/Admin/Improve/Design/MailTheme/preview.html.twig', [
            'layoutHeaderToolbarBtn' => [],
            'layoutTitle' => $this->trans('Preview Theme %s', 'Admin.Design.Feature', [$mailTheme->getName()]),
            'enableSidebar' => true,
            'help_link' => $this->generateSidebarLink($legacyController),
            'mailTheme' => $mailTheme,
        ]);
    }

    /**
     * This action allows to send a test mail of a specific email template, however the Mail
     * class used to send emails is not modular enough to allow sending templates on the fly.
     * This would require either:
     *  - a little modification of the Mail class to add an easy way to send a template content (rather than its name)
     *  - a full refacto of the Mail class which wouldn't be coupled to static files any more
     *
     * These modifications will be performed in a future release so for now we can only send test emails
     * with the current email theme using generated static files.
     *
     * @AdminSecurity("is_granted('read', request.get('_legacy_controller'))")
     *
     * @param string $theme
     * @param string $layout
     * @param string $locale
     * @param string $module
     *
     * @return Response
     *
     * @throws InvalidArgumentException
     */
    public function sendTestMailAction($theme, $layout, $locale, $module = '')
    {
        if ($this->getConfiguration()->get('PS_MAIL_THEME') !== $theme) {
            $this->addFlash(
                'error',
                $this->trans(
                    'Cannot send test email for theme %theme% because it is not your current theme',
                    'Admin.Notifications.Error',
                    [
                        '%theme%' => $theme,
                    ]
                )
            );

            return $this->redirectToRoute('admin_mail_theme_preview', ['theme' => $theme]);
        }

        /** @var ContextEmployeeProviderInterface $employeeProvider */
        $employeeProvider = $this->get('prestashop.adapter.data_provider.employee');
        $employeeData = $employeeProvider->getData();

        /** @var LanguageRepositoryInterface $languageRepository */
        $languageRepository = $this->get('prestashop.core.admin.lang.repository');
        $language = $languageRepository->getOneByLocaleOrIsoCode($locale);
        if (null === $language) {
            throw new InvalidArgumentException(sprintf('Cannot find Language with locale or isoCode %s', $locale));
        }

        if (empty($module)) {
            $templatePath = _PS_MAIL_DIR_;
        } else {
            $templatePath = _PS_MODULE_DIR_ . $module . '/mails/';
        }

        /** @var MailPreviewVariablesBuilder $variablesBuilder */
        $variablesBuilder = $this->get('prestashop.adapter.mail_template.preview_variables_builder');
        $mailLayout = $this->getMailLayout($theme, $layout, $module);
        $mailVariables = $variablesBuilder->buildTemplateVariables($mailLayout);

        $mailSent = Mail::send(
            $language->getId(),
            $layout,
            $this->trans('Test email %template%', 'Admin.Design.Feature', ['%template%' => $layout]),
            $mailVariables,
            $employeeData['email'],
            $employeeData['firstname'] . ' ' . $employeeData['lastname'],
            $employeeData['email'],
            $employeeData['firstname'] . ' ' . $employeeData['lastname'],
            null,
            null,
            $templatePath
        );

        if ($mailSent) {
            $this->addFlash(
                'success',
                $this->trans(
                    'Test email for layout %layout% was successfully sent to %email%',
                    'Admin.Notifications.Success',
                    [
                        '%layout%' => $layout,
                        '%email%' => $employeeData['email'],
                    ]
                )
            );
        } else {
            $this->addFlash(
                'error',
                $this->trans(
                    'Cannot send test email for layout %layout%',
                    'Admin.Notifications.Error',
                    [
                        '%layout%' => $layout,
                    ]
                )
            );
        }

        return $this->redirectToRoute('admin_mail_theme_preview', ['theme' => $theme]);
    }

    /**
     * @AdminSecurity(
     *     "is_granted('update', request.get('_legacy_controller'))",
     *     message="You do not have permission to update this."
     * )
     *
     * @param Request $request
     *
     * @return \Symfony\Component\HttpFoundation\RedirectResponse
     */
    public function translateBodyAction(Request $request)
    {
        $translateMailsBodyForm = $this->createForm(TranslateMailsBodyType::class);
        $translateMailsBodyForm->handleRequest($request);

        if (!$translateMailsBodyForm->isSubmitted() || !$translateMailsBodyForm->isValid()) {
            $this->addFlash(
                'error',
                $this->trans(
                    'Cannot translate emails body content',
                    'Admin.Notifications.Error'
                )
            );

            return $this->redirectToRoute('admin_mail_theme_index');
        }

        $translateData = $translateMailsBodyForm->getData();
        $language = $translateData['language'];
        /** @var TranslationService $translationService */
        $translationService = $this->get('prestashop.service.translation');
        $locale = $translationService->langToLocale($language);

        return $this->redirectToRoute('admin_international_translation_overview', [
            'lang' => $language,
            'locale' => $locale,
            'type' => 'mails_body',
        ]);
    }

    /**
     * Preview a mail layout from a defined theme
     *
     * @AdminSecurity("is_granted('read', request.get('_legacy_controller'))")
     *
     * @param string $theme
     * @param string $layout
     * @param string $type
     * @param string $locale
     * @param string $module
     *
     * @return Response
     *
     * @throws FileNotFoundException
     * @throws InvalidArgumentException
     */
    public function previewLayoutAction($theme, $layout, $type, $locale, $module = '')
    {
        $renderedLayout = $this->renderLayout($theme, $layout, $type, $locale, $module);

        return new Response($renderedLayout);
    }

    /**
     * Display the raw source of a theme layout (mainly useful for developers/integrators)
     *
     * @AdminSecurity("is_granted('read', request.get('_legacy_controller'))")
     *
     * @param string $theme
     * @param string $layout
     * @param string $type
     * @param string $locale
     * @param string $module
     *
     * @return Response
     *
     * @throws FileNotFoundException
     * @throws InvalidArgumentException
     */
    public function rawLayoutAction($theme, $layout, $type, $locale, $module = '')
    {
        $renderedLayout = $this->renderLayout($theme, $layout, $type, $locale, $module);

        $response = new Response($renderedLayout, Response::HTTP_OK, [
            'Content-Type' => 'text/plain',
        ]);

        return $response;
    }

    /**
     * Dynamically display an email template, this is usually used by the MailGenerator but this action
     * allows to display preview before generating the file (handy when you are developing an email theme)
     *
     * @param string $themeName
     * @param string $layoutName
     * @param string $type
     * @param string $locale
     * @param string $module
     *
     * @return string
     *
     * @throws FileNotFoundException
     * @throws InvalidArgumentException
     */
    private function renderLayout($themeName, $layoutName, $type, $locale = '', $module = '')
    {
        $layout = $this->getMailLayout($themeName, $layoutName, $module);

        /** @var LanguageRepositoryInterface $languageRepository */
        $languageRepository = $this->get('prestashop.core.admin.lang.repository');
        if (empty($locale)) {
            $locale = $this->getContext()->language->locale;
        }
        $language = $languageRepository->getOneByLocaleOrIsoCode($locale);
        if (null === $language) {
            throw new InvalidArgumentException(sprintf('Cannot find Language with locale or isoCode %s', $locale));
        }

        /** @var MailPreviewVariablesBuilder $variablesBuilder */
        $variablesBuilder = $this->get('prestashop.adapter.mail_template.preview_variables_builder');
        $mailLayoutVariables = $variablesBuilder->buildTemplateVariables($layout);

        /** @var MailTemplateRendererInterface $renderer */
        $renderer = $this->get('prestashop.core.mail_template.mail_template_renderer');
        //Special case for preview, we fill the mail variables
        $renderer->addTransformation(new MailVariablesTransformation(MailTemplateInterface::HTML_TYPE, $mailLayoutVariables));
        $renderer->addTransformation(new MailVariablesTransformation(MailTemplateInterface::TXT_TYPE, $mailLayoutVariables));

        switch ($type) {
            case MailTemplateInterface::HTML_TYPE:
                $renderedLayout = $renderer->renderHtml($layout, $language);
                break;
            case MailTemplateInterface::TXT_TYPE:
                $renderedLayout = $renderer->renderTxt($layout, $language);
                break;
            default:
                throw new NotFoundHttpException(sprintf('Requested type %s is not managed, please use one of these: %s', $type, implode(',', [MailTemplateInterface::HTML_TYPE, MailTemplateInterface::TXT_TYPE])));
        }

        return $renderedLayout;
    }

    /**
     * @param string $themeName
     * @param string $layoutName
     * @param string $module
     *
     * @return LayoutInterface
     *
     * @throws FileNotFoundException
     * @throws InvalidArgumentException
     */
    private function getMailLayout($themeName, $layoutName, $module)
    {
        /** @var ThemeCatalogInterface $themeCatalog */
        $themeCatalog = $this->get('prestashop.core.mail_template.theme_catalog');
        /** @var ThemeInterface $theme */
        $theme = $themeCatalog->getByName($themeName);

        /** @var LayoutInterface $layout */
        $layout = null;
        /* @var LayoutInterface $layoutInterface */
        foreach ($theme->getLayouts() as $layoutInterface) {
            if ($layoutInterface->getName() == $layoutName
                && $layoutInterface->getModuleName() == $module
            ) {
                $layout = $layoutInterface;
                break;
            }
        }

        if (null === $layout) {
            throw new FileNotFoundException(sprintf('Cannot find layout %s%s in theme %s', empty($module) ? '' : $module . ':', $layoutName, $themeName));
        }

        return $layout;
    }

    /**
     * @return FormHandlerInterface
     */
    private function getMailThemeFormHandler(): FormHandlerInterface
    {
        return $this->get('prestashop.admin.mail_theme.form_handler');
    }
}