vendor/contao/newsletter-bundle/src/Resources/contao/modules/ModuleUnsubscribe.php line 34

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of Contao.
  4.  *
  5.  * (c) Leo Feyer
  6.  *
  7.  * @license LGPL-3.0-or-later
  8.  */
  9. namespace Contao;
  10. /**
  11.  * Front end module "newsletter unsubscribe".
  12.  *
  13.  * @property bool   $nl_hideChannels
  14.  * @property string $nl_unsubscribe
  15.  * @property array  $nl_channels
  16.  * @property string $nl_template
  17.  */
  18. class ModuleUnsubscribe extends Module
  19. {
  20.     /**
  21.      * Template
  22.      * @var string
  23.      */
  24.     protected $strTemplate 'nl_default';
  25.     /**
  26.      * Display a wildcard in the back end
  27.      *
  28.      * @return string
  29.      */
  30.     public function generate()
  31.     {
  32.         $request System::getContainer()->get('request_stack')->getCurrentRequest();
  33.         if ($request && System::getContainer()->get('contao.routing.scope_matcher')->isBackendRequest($request))
  34.         {
  35.             $objTemplate = new BackendTemplate('be_wildcard');
  36.             $objTemplate->wildcard '### ' $GLOBALS['TL_LANG']['FMD']['unsubscribe'][0] . ' ###';
  37.             $objTemplate->title $this->headline;
  38.             $objTemplate->id $this->id;
  39.             $objTemplate->link $this->name;
  40.             $objTemplate->href StringUtil::specialcharsUrl(System::getContainer()->get('router')->generate('contao_backend', array('do'=>'themes''table'=>'tl_module''act'=>'edit''id'=>$this->id)));
  41.             return $objTemplate->parse();
  42.         }
  43.         $this->nl_channels StringUtil::deserialize($this->nl_channels);
  44.         // Return if there are no channels
  45.         if (empty($this->nl_channels) || !\is_array($this->nl_channels))
  46.         {
  47.             return '';
  48.         }
  49.         return parent::generate();
  50.     }
  51.     /**
  52.      * Generate the module
  53.      */
  54.     protected function compile()
  55.     {
  56.         // Overwrite default template
  57.         if ($this->nl_template)
  58.         {
  59.             $this->Template = new FrontendTemplate($this->nl_template);
  60.             $this->Template->setData($this->arrData);
  61.         }
  62.         $this->Template->email '';
  63.         $this->Template->captcha '';
  64.         $objWidget null;
  65.         // Set up the captcha widget
  66.         if (!$this->disableCaptcha)
  67.         {
  68.             $arrField = array
  69.             (
  70.                 'name' => 'unsubscribe_' $this->id,
  71.                 'label' => $GLOBALS['TL_LANG']['MSC']['securityQuestion'],
  72.                 'inputType' => 'captcha',
  73.                 'eval' => array('mandatory'=>true)
  74.             );
  75.             $objWidget = new FormCaptcha(FormCaptcha::getAttributesFromDca($arrField$arrField['name']));
  76.         }
  77.         $strFormId 'tl_unsubscribe_' $this->id;
  78.         // Unsubscribe
  79.         if (Input::post('FORM_SUBMIT') == $strFormId)
  80.         {
  81.             $varSubmitted $this->validateForm($objWidget);
  82.             if ($varSubmitted !== false)
  83.             {
  84.                 $this->removeRecipient(...$varSubmitted);
  85.             }
  86.         }
  87.         // Add the captcha widget to the template
  88.         if ($objWidget !== null)
  89.         {
  90.             $this->Template->captcha $objWidget->parse();
  91.         }
  92.         $session System::getContainer()->get('session');
  93.         // Confirmation message
  94.         if ($session->isStarted())
  95.         {
  96.             $flashBag $session->getFlashBag();
  97.             if ($flashBag->has('nl_removed'))
  98.             {
  99.                 $arrMessages $flashBag->get('nl_removed');
  100.                 $this->Template->mclass 'confirm';
  101.                 $this->Template->message $arrMessages[0];
  102.             }
  103.         }
  104.         $arrChannels = array();
  105.         $objChannel NewsletterChannelModel::findByIds($this->nl_channels);
  106.         // Get the titles
  107.         if ($objChannel !== null)
  108.         {
  109.             while ($objChannel->next())
  110.             {
  111.                 $arrChannels[$objChannel->id] = $objChannel->title;
  112.             }
  113.         }
  114.         // Default template variables
  115.         $this->Template->channels $arrChannels;
  116.         $this->Template->showChannels = !$this->nl_hideChannels;
  117.         $this->Template->email Input::get('email');
  118.         $this->Template->submit StringUtil::specialchars($GLOBALS['TL_LANG']['MSC']['unsubscribe']);
  119.         $this->Template->channelsLabel $GLOBALS['TL_LANG']['MSC']['nl_channels'];
  120.         $this->Template->emailLabel $GLOBALS['TL_LANG']['MSC']['emailAddress'];
  121.         $this->Template->formId $strFormId;
  122.         $this->Template->id $this->id;
  123.         $this->Template->requestToken System::getContainer()->get('contao.csrf.token_manager')->getDefaultTokenValue();
  124.     }
  125.     /**
  126.      * Validate the subscription form
  127.      *
  128.      * @param Widget $objWidget
  129.      *
  130.      * @return array|bool
  131.      */
  132.     protected function validateForm(Widget $objWidget=null)
  133.     {
  134.         // Validate the e-mail address
  135.         $varInput Idna::encodeEmail(Input::post('email'true));
  136.         if (!Validator::isEmail($varInput))
  137.         {
  138.             $this->Template->mclass 'error';
  139.             $this->Template->message $GLOBALS['TL_LANG']['ERR']['email'];
  140.             return false;
  141.         }
  142.         $this->Template->email $varInput;
  143.         // Validate the channel selection
  144.         $arrChannels Input::post('channels');
  145.         if (!\is_array($arrChannels))
  146.         {
  147.             $this->Template->mclass 'error';
  148.             $this->Template->message $GLOBALS['TL_LANG']['ERR']['noChannels'];
  149.             return false;
  150.         }
  151.         $arrChannels array_intersect($arrChannels$this->nl_channels); // see #3240
  152.         if (empty($arrChannels) || !\is_array($arrChannels))
  153.         {
  154.             $this->Template->mclass 'error';
  155.             $this->Template->message $GLOBALS['TL_LANG']['ERR']['noChannels'];
  156.             return false;
  157.         }
  158.         $this->Template->selectedChannels $arrChannels;
  159.         // Check if there are any new subscriptions
  160.         $arrSubscriptions = array();
  161.         if (($objSubscription NewsletterRecipientsModel::findBy(array("email=? AND active='1'"), $varInput)) !== null)
  162.         {
  163.             $arrSubscriptions $objSubscription->fetchEach('pid');
  164.         }
  165.         $arrChannels array_intersect($arrChannels$arrSubscriptions);
  166.         if (empty($arrChannels))
  167.         {
  168.             $this->Template->mclass 'error';
  169.             $this->Template->message $GLOBALS['TL_LANG']['ERR']['unsubscribed'];
  170.             return false;
  171.         }
  172.         // Validate the captcha
  173.         if ($objWidget !== null)
  174.         {
  175.             $objWidget->validate();
  176.             if ($objWidget->hasErrors())
  177.             {
  178.                 return false;
  179.             }
  180.         }
  181.         return array($varInput$arrChannels);
  182.     }
  183.     /**
  184.      * Remove the recipient
  185.      *
  186.      * @param string $strEmail
  187.      * @param array  $arrRemove
  188.      */
  189.     protected function removeRecipient($strEmail$arrRemove)
  190.     {
  191.         // Remove the subscriptions
  192.         if (($objRemove NewsletterRecipientsModel::findByEmailAndPids($strEmail$arrRemove)) !== null)
  193.         {
  194.             while ($objRemove->next())
  195.             {
  196.                 $strHash md5($objRemove->email);
  197.                 // Add a deny list entry (see #4999)
  198.                 if (NewsletterDenyListModel::findByHashAndPid($strHash$objRemove->pid) === null)
  199.                 {
  200.                     $objDenyList = new NewsletterDenyListModel();
  201.                     $objDenyList->pid $objRemove->pid;
  202.                     $objDenyList->hash $strHash;
  203.                     $objDenyList->save();
  204.                 }
  205.                 $objRemove->delete();
  206.             }
  207.         }
  208.         // Get the channels
  209.         $objChannels NewsletterChannelModel::findByIds($arrRemove);
  210.         $arrChannels $objChannels->fetchEach('title');
  211.         // HOOK: post unsubscribe callback
  212.         if (isset($GLOBALS['TL_HOOKS']['removeRecipient']) && \is_array($GLOBALS['TL_HOOKS']['removeRecipient']))
  213.         {
  214.             foreach ($GLOBALS['TL_HOOKS']['removeRecipient'] as $callback)
  215.             {
  216.                 $this->import($callback[0]);
  217.                 $this->{$callback[0]}->{$callback[1]}($strEmail$arrRemove$this);
  218.             }
  219.         }
  220.         // Prepare the simple token data
  221.         $arrData = array();
  222.         $arrData['domain'] = Idna::decode(Environment::get('host'));
  223.         $arrData['channel'] = $arrData['channels'] = implode("\n"$arrChannels);
  224.         // Confirmation e-mail
  225.         $objEmail = new Email();
  226.         $objEmail->from $GLOBALS['TL_ADMIN_EMAIL'] ?? null;
  227.         $objEmail->fromName $GLOBALS['TL_ADMIN_NAME'] ?? null;
  228.         $objEmail->subject sprintf($GLOBALS['TL_LANG']['MSC']['nl_subject'], Idna::decode(Environment::get('host')));
  229.         $objEmail->text System::getContainer()->get('contao.string.simple_token_parser')->parse($this->nl_unsubscribe$arrData);
  230.         $objEmail->sendTo($strEmail);
  231.         // Redirect to the jumpTo page
  232.         if (($objTarget $this->objModel->getRelated('jumpTo')) instanceof PageModel)
  233.         {
  234.             /** @var PageModel $objTarget */
  235.             $this->redirect($objTarget->getFrontendUrl());
  236.         }
  237.         System::getContainer()->get('session')->getFlashBag()->set('nl_removed'$GLOBALS['TL_LANG']['MSC']['nl_removed']);
  238.         $this->reload();
  239.     }
  240. }
  241. class_alias(ModuleUnsubscribe::class, 'ModuleUnsubscribe');