bundles/ProtectoBundle/EventListener/UserListener.php line 50

Open in your IDE?
  1. <?php
  2. namespace ProtectoBundle\EventListener;
  3. use Exception;
  4. use Pimcore\Config;
  5. use Pimcore\Event\Model\DataObjectEvent;
  6. use Pimcore\Event\Model\ElementEventInterface;
  7. use Pimcore\Mail;
  8. use Pimcore\Model\DataObject\Representative;
  9. use Pimcore\Model\DataObject\User;
  10. use Pimcore\Model\Element\Service;
  11. use Pimcore\Model\WebsiteSetting;
  12. use Symfony\Component\HttpFoundation\Response;
  13. class UserListener
  14. {
  15.     /**
  16.      * Before adding a User
  17.      *
  18.      * @param ElementEventInterface $e
  19.      * @return void
  20.      */
  21.     public function onPreAdd(ElementEventInterface $e)
  22.     {
  23.         if ($e instanceof DataObjectEvent) {
  24.             $user $e->getObject();
  25.             if ($user instanceof User) {
  26.                 // if User has no username (e.g. if User created via Pimcore Backend)
  27.                 if (!$user->getUsername()) {
  28.                     // Fallback => use key as username
  29.                     $user->setUsername($user->getKey());
  30.                 }
  31.                 // override key with validated username
  32.                 $user->setKey(Service::getValidKey($user->getUsername(), 'object'));
  33.                 // unpublish user, so has to wait for publishing from the representative
  34.                 $user->setPublished(false);
  35.             }
  36.         }
  37.     }
  38.     /**
  39.      * After adding a User
  40.      *
  41.      * @param ElementEventInterface $e
  42.      * @return void
  43.      * @throws Exception
  44.      */
  45.     public function onPostAdd(ElementEventInterface $e)
  46.     {
  47.         if ($e instanceof DataObjectEvent) {
  48.             $user $e->getObject();
  49.             if ($user instanceof User) {
  50.                 $this->matchUserToRepresentative($user->getId());
  51.             }
  52.         }
  53.     }
  54.     /**
  55.      * Finds the matching Representative to the given User zip
  56.      *
  57.      * @param int $userId
  58.      * @return Response
  59.      * @throws Exception
  60.      */
  61.     public function matchUserToRepresentative(int $userId): Response
  62.     {
  63.         $user User::getById($userId);
  64.         // remove whitespaces from zip
  65.         $user->setZip(preg_replace("/\s/i"""$user->getZip()));
  66.         $userZipStr $user->getZip();
  67.         // country has to be filled for export representative
  68.         if (!empty($user->getCountry())) {
  69.             // for any user outside of 'Germany'
  70.             if ($user->getCountry() !== 'Germany') {
  71.                 // export representative
  72.                 $repExport Representative::getByPath('/Vertreter/export');
  73.                 return $this->submitMatching($user$repExport);
  74.             }
  75.         }
  76.         // prepare zip for matching
  77.         $userZipFull $this->getZipFull($userZipStr);
  78.         // use floatval to prevent matching errors
  79.         $userZipFloat floatval($userZipFull);
  80.         // if User zip exists, but it's floatval is not greater than 0
  81.         if ($userZipStr && !floatval($userZipStr) > 0) {
  82.             throw new Exception('invalid zip');
  83.         }
  84.         $repListing = new Representative\Listing();
  85.         $repListing->load();
  86.         $repListingData $repListing->getData();
  87.         foreach ($repListingData as $rep) {
  88.             foreach ($rep->getZip() as $repZip) {
  89.                 // read "from" and "to" zips to prepare them like in User
  90.                 $repZipFromStr $repZip["from"]->getData();
  91.                 $repZipFromFull $this->getZipFull($repZipFromStr);
  92.                 $repZipFromFloat floatval($repZipFromFull);
  93.                 $repZipToStr $repZip["to"]->getData();
  94.                 $repZipToFull $this->getZipFull($repZipToStr);
  95.                 $repZipToFloat floatval($repZipToFull);
  96.                 // if exact match - also covers the case if there is only "from" or only "to" (non-range)
  97.                 if ($userZipStr === $repZipFromStr || $userZipStr === $repZipToStr) {
  98.                     return $this->submitMatching($user$rep);
  99.                 } else {
  100.                     // if valid range is defined
  101.                     if (floatval($repZipFromStr) > && floatval($repZipToStr) > 0) {
  102.                         // resort asc to prevent wrong input-behaviour
  103.                         $sortedRange = [$repZipFromFloat$repZipToFloat];
  104.                         sort($sortedRange);
  105.                         // if User zip is in that valid range
  106.                         if ($userZipFloat >= $sortedRange[0] && $userZipFloat <= $sortedRange[1]) {
  107.                             return $this->submitMatching($user$rep);
  108.                         }
  109.                     }
  110.                 }
  111.             }
  112.         }
  113.         // default representative
  114.         $repDefault Representative::getByPath('/Vertreter/default');
  115.         // if no representative was found yet from registering via frontend
  116.         if (!empty($user->getZip()) && !empty($user->getCountry())) {
  117.             // match default representative and send mails to it's recipients (without extra bcc for default to prevent duplicate mails!)
  118.             return $this->submitMatching($user$repDefaultfalse);
  119.         }
  120.         /*
  121.             if not even yet a representative was found (e.g. if User created via Pimcore Backend),
  122.             set default representative as fallback, but DON'T send mails to it's recipients;
  123.             in this case a Pimcore Backend User has to edit, save and publish that user manually!
  124.         */
  125.         $user->setRepresentative($repDefault);
  126.         $user->save();
  127.         return new Response();
  128.     }
  129.     /**
  130.      * saves Representative relation in the User and sends according mails to the affected.
  131.      *
  132.      * @param User $user - user to match with a representative
  133.      * @param Representative $rep - representative to save in the user
  134.      * @param bool $bccForDefault - sends mail copies to the recipients of the default representative
  135.      * @return Response
  136.      * @throws Exception
  137.      */
  138.     public function submitMatching(User $userRepresentative $repbool $bccForDefault true): Response
  139.     {
  140.         // save representative first, even if following code breaks
  141.         $user->setRepresentative($rep);
  142.         $user->save();
  143.         // read main domain for userDeeplink
  144.         $mainDomain Config::getSystemConfiguration()["general"]['domain'];
  145.         // if missing System Settings "Main Domain", cancel submit and mail sending to prevent wrong userDeeplink in mails
  146.         if (!$mainDomain) {
  147.             throw new Exception('missing "System Settings" > "Website" > "Main Domain"');
  148.         }
  149.         // determine server side protocol for userDeeplink usage
  150.         $protocol = isset($_SERVER['HTTPS']) && !empty($_SERVER['HTTPS']) ? 'https' 'http';
  151.         // default representative
  152.         $repDefault Representative::getByPath('/Vertreter/default');
  153.         // set mail variables for the document
  154.         $repMailParams = [
  155.             'userCustomerId' => $user->getCustomerId(),
  156.             'userForename' => $user->getForename(),
  157.             'userSurname' => $user->getSurname(),
  158.             'userCompany' => $user->getCompany(),
  159.             'userStreet' => $user->getStreet(),
  160.             'userStreetNo' => $user->getStreetNo(),
  161.             'userZip' => $user->getZip(),
  162.             'userCity' => $user->getCity(),
  163.             'userCountry' => $user->getCountry(),
  164.             'userUsername' => $user->getUsername(),
  165.             'userRegistrationDate' => date_format(date_create()->setTimestamp($user->getCreationDate()), "d.m.Y"),
  166.             'userDeeplink' => "$protocol://$mainDomain/admin/login/deeplink?object_{$user->getId()}_object"
  167.         ];
  168.         if ($bccForDefault) {
  169.             // all default representative recipients get a mail that someone has registered
  170.             foreach ($repDefault->getEmailRecipients() as $repRecipient) {
  171.                 // remove reference of $repMailParams and merge current representative infos
  172.                 $params array_merge($repMailParams, [
  173.                     'forename' => $repDefault->getForename(),
  174.                     'surname' => $repDefault->getSurname(),
  175.                     'username' => $repDefault->getUsername()
  176.                 ]);
  177.                 $this->sendMail($repRecipient["address"]->getData(), "Neue Registrierung"$params"/Email/representativeUserRegistered");
  178.             }
  179.         }
  180.         // all matched representative recipients get a mail that someone has registered
  181.         foreach ($rep->getEmailRecipients() as $repRecipient) {
  182.             // remove reference of $repMailParams and merge current representative infos
  183.             $params array_merge($repMailParams, [
  184.                 'forename' => $rep->getForename(),
  185.                 'surname' => $rep->getSurname(),
  186.                 'username' => $rep->getUsername()
  187.             ]);
  188.             $this->sendMail($repRecipient["address"]->getData(), "Neue Registrierung"$params"/Email/representativeUserRegistered");
  189.         }
  190.         // set mail variables for the document
  191.         $userMailParams = [
  192.             'customerId' => $user->getCustomerId(),
  193.             'forename' => $user->getForename(),
  194.             'surname' => $user->getSurname(),
  195.             'company' => $user->getCompany(),
  196.             'street' => $user->getStreet(),
  197.             'streetNo' => $user->getStreetNo(),
  198.             'zip' => $user->getZip(),
  199.             'city' => $user->getCity(),
  200.             'country' => $user->getCountry(),
  201.             'username' => $user->getUsername(),
  202.             'registrationDate' => date_format(date_create()->setTimestamp($user->getCreationDate()), "d.m.Y")
  203.         ];
  204.         // user gets confirmation mail (user is registered)
  205.         $this->sendMail($user->getUsername(), "Registrierungsbestätigung"$userMailParams"/Email/userRegistered");
  206.         return new Response();
  207.     }
  208.     /**
  209.      * sends a mail to a recipient, with given params for a document
  210.      *
  211.      * @param string $recipient
  212.      * @param string $subject
  213.      * @param array $params
  214.      * @param string $document
  215.      * @return void
  216.      * @throws Exception
  217.      */
  218.     private function sendMail(string $recipientstring $subject, array $paramsstring $document)
  219.     {
  220.         $mail = new Mail();
  221.         $mail->to($recipient);
  222.         $mail->setSubject($subject);
  223.         $mail->setDocument($document);
  224.         $mail->setParams($params);
  225.         $mail->send();
  226.     }
  227.     /**
  228.      * Description:
  229.      * - read and prepare zip as full string for error-prevention
  230.      * - floating-prefix inclusive, so the range don't gets destroyed and leading zeros don't get cut off
  231.      * - e.g. zip is 090 is greater than 0100, so 0.09000 is greater than 0.01000
  232.      * - default zip length 5 (=german zip)
  233.      *
  234.      * Functionality (in this example zipLength === 5):
  235.      * - leading zeros won't be cut off for calculation (00098 remains 00098 for calculation and won't get parsed to 98)
  236.      * - following zeros will be added automatically for calculation (12 will be calculated as 12000)
  237.      * - so a range of 00098 to 12 equals 00098-12000
  238.      *
  239.      * Explanation:
  240.      * Some German zips for example can begin with leading zeros like 01000 and 09660.
  241.      * Another valid equivalent writing form for those would be 01 and 0966.
  242.      * So the following zeros aren't necessary for spelling, but the leading zeros are!
  243.      * For better understanding, one could read those as 01*** and 0966* for example.
  244.      * Very important is, that leading zeros don't get cut off because that would manipulate the whole numeric value,
  245.      * for example 00009 to 10000 would be a range of 9 to 1 instead of 9 to 10000, because of the missing leading zeros!
  246.      *
  247.      * @param string $zip
  248.      * @param int $zipLength
  249.      * @return string
  250.      */
  251.     public function getZipFull(string $zipint $zipLength 5): string
  252.     {
  253.         return str_pad("0.$zip"$zipLength 2"0");
  254.     }
  255.     /**
  256.      * After updating a User
  257.      *
  258.      * @param ElementEventInterface $e
  259.      * @return void
  260.      * @throws Exception
  261.      */
  262.     public function onPostUpdate(ElementEventInterface $e)
  263.     {
  264.         if ($e instanceof DataObjectEvent) {
  265.             $user $e->getObject();
  266.             if ($user instanceof User) {
  267.                 // auto-save should NOT trigger this procedure to prevent unintentional mails - only manual saves should
  268.                 if (!$e->hasArgument("isAutoSave") || ($e->hasArgument("isAutoSave") && !$e->getArgument("isAutoSave"))) {
  269.                     // if missing mediaDbUrl, cancel mail and initialPublished process
  270.                     if (!WebsiteSetting::getByName('mediaDbUrl')) {
  271.                         throw new Exception('missing "Website Settings" > Name: "mediaDbUrl"');
  272.                     }
  273.                     // only if updated user gets published initially
  274.                     if ($user->getPublished() && !$user->getInitialPublished()) {
  275.                         // EVERY TIME a user gets published INITIALLY generate a new temporary User password string to send via mail
  276.                         $newPw bin2hex(openssl_random_pseudo_bytes(3)) . substr(str_shuffle('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'), 04);
  277.                         // Override current password!
  278.                         $user->setPassword($newPw);
  279.                         // set mail variables for the document incl. loginLink from WebsiteSetting
  280.                         $userMailParams = [
  281.                             'customerId' => $user->getCustomerId(),
  282.                             'forename' => $user->getForename(),
  283.                             'surname' => $user->getSurname(),
  284.                             'company' => $user->getCompany(),
  285.                             'street' => $user->getStreet(),
  286.                             'streetNo' => $user->getStreetNo(),
  287.                             'zip' => $user->getZip(),
  288.                             'city' => $user->getCity(),
  289.                             'country' => $user->getCountry(),
  290.                             'username' => $user->getUsername(),
  291.                             'newTemporaryPassword' => $newPw,
  292.                             'registrationDate' => date_format(date_create()->setTimestamp($user->getCreationDate()), "d.m.Y"),
  293.                             'mediaDbLink' => WebsiteSetting::getByName('mediaDbUrl')->getData()
  294.                         ];
  295.                         // user gets confirmation mail (user is published)
  296.                         $this->sendMail($user->getUsername(), "Freischaltung"$userMailParams"/Email/userPublished");
  297.                         // user shouldn't get publishing mails afterwards
  298.                         $user->setInitialPublished(true);
  299.                         $user->save();
  300.                     }
  301.                 }
  302.             }
  303.         }
  304.     }
  305. }