<?php
namespace CoreBundle\Controller;
use CoreBundle\Form\RequestPasswordResetFormType;
use CoreBundle\Form\ResetPasswordFormType;
use CoreBundle\Model\Customer;
use CoreBundle\Form\LoginFormType;
use CoreBundle\Form\RegistrationFormHandler;
use CoreBundle\Form\RegistrationFormType;
use CustomerManagementFrameworkBundle\CustomerProvider\CustomerProviderInterface;
use CustomerManagementFrameworkBundle\CustomerSaveValidator\Exception\DuplicateCustomerException;
use CustomerManagementFrameworkBundle\Security\Authentication\LoginManagerInterface;
use CustomerManagementFrameworkBundle\Security\OAuth\Exception\AccountNotLinkedException;
use CustomerManagementFrameworkBundle\Security\OAuth\OAuthRegistrationHandler;
use Pimcore\Bundle\EcommerceFrameworkBundle\EnvironmentInterface;
use Pimcore\Bundle\EcommerceFrameworkBundle\IEnvironment;
use Pimcore\Mail;
use Pimcore\Model\Document;
use Pimcore\Model\Site;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use \Pimcore\Model\DataObject;
use \Pimcore\Model\DataObject\OnlineShopOrder\Listing;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; //important for annotation!
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; //important for annotation!
//use CoreBundle\Controller\SecureController;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
class AccountController extends AbstractController
{
CONST TOKEN_DIGIT_SIZE = 12;
CONST EMAIL_CUSTOMER_REGISTER = "/mail/customerRegister";
CONST EMAIL_CUSTOMER_PW_RESET = "/mail/passwordReset";
/**
* @param Request $request
* @param CustomerProviderInterface $customerProvider
* @param LoginManagerInterface $loginManager
* @param RegistrationFormHandler $registrationFormHandler
* @param UserInterface|null $user
* @param SessionInterface $session
* @param IEnvironment $environment
* @return \Symfony\Component\HttpFoundation\RedirectResponse
*/
public function registerAction(
Request $request,
CustomerProviderInterface $customerProvider,
LoginManagerInterface $loginManager,
RegistrationFormHandler $registrationFormHandler,
UserInterface $user = null,
SessionInterface $session,
EnvironmentInterface $environment
) {
//redirect user to index page if logged in
if ($user && $this->isGranted('ROLE_USER')) {
return $this->redirectToRoute('acc_index', ['controller' => 'account', 'action' => 'index']);
}
$registrationKey = $request->get('registrationKey');
// create a new, empty customer instance
$customer = $customerProvider->create();
// the registration form handler is just a utility class to map pimcore object data to form
$formData = $registrationFormHandler->buildFormData($customer);
$hidePassword = false;
// build the registration form and pre-fill it with customer data
$form = $this->createForm(RegistrationFormType::class, $formData, ['hidePassword' => $hidePassword]);
$form->handleRequest($request);
$errors = [];
if ($form->isSubmitted() && $form->isValid()) {
$registrationFormHandler->updateCustomerFromForm($customer, $form);
$customer->setActive(true);
try {
$token = $this->generateToken();
$customer->setEmailConfirmToken($token);
$customer->save();
//check if special redirect is necessary
if($session->get("referrer")) {
$response = $this->redirect($session->get("referrer"));
$session->remove("referrer");
} else {
$response = $this->redirectToRoute('acc_index', ['controller' => 'account', 'action' => 'index']);
}
// log user in manually
// pass response to login manager as it adds potential remember me cookies
$loginManager->login($customer, $request, $response);
$environment->setCurrentUserId($customer->getId());
$environment->save();
return $response;
} catch (DuplicateCustomerException $e) {
$errors[] = 'Customer already exists';
} catch (\Exception $e) {
$errors[] = $e->getMessage();
}
}
if($form->isSubmitted() && !$form->isValid()) {
foreach($form->getErrors() as $error) {
$errors[] = $error->getMessage();
}
foreach($form->all()['captcha']->getErrors() as $error) {
$errors[] = $error->getMessage();
}
}
$this->view->customer = $customer;
$this->view->form = $form->createView();
$this->view->errors = $errors;
$this->view->hideNav = true;
$this->view->hideBreadcrumb = true;
$this->view->hidePassword = $hidePassword;
}
/**
* @param AuthenticationUtils $authenticationUtils
* @param UserInterface|null $user
* @return \Symfony\Component\HttpFoundation\RedirectResponse
* @throws \Exception
*/
public function loginAction(
AuthenticationUtils $authenticationUtils,
// OAuthRegistrationHandler $oAuthHandler,
UserInterface $user = null, Request $request
)
{
//redirect user to index page if logged in, write User ID to cart
if ($user && $this->isGranted('ROLE_USER')) {
$cart = $this->getCart();
$cart->setUserId($user->getId());
$cart->save();
return $this->redirectToRoute('acc_index', ['controller' => 'account', 'action' => 'index']);
}
// get the login error if there is one
$error = $authenticationUtils->getLastAuthenticationError();
// last username entered by the user
$lastUsername = $authenticationUtils->getLastUsername();
$formData = [
'_username' => $lastUsername
];
$form = $this->createForm(LoginFormType::class, $formData, [
'action' => $this->generateUrl('login'),
]);
$this->view->reset = (bool)$request->get('reset');
$this->view->success = (bool)$request->get('success'); // After PW was successfully reset
$this->view->user = $user;
$this->view->form = $form->createView();
$this->view->error = $error;
$this->view->hideNav = true;
$this->view->hideBreadcrumb = true;
}
/**
* @param UserInterface|null $user
* @return RedirectResponse
*/
private function buildUserRedirect(UserInterface $user = null): RedirectResponse
{
if ($user!=null && $this->isGranted('ROLE_USER')) {
return $this->redirectToRoute('acc_index');
}
return $this->redirectToRoute('login');
}
/**
* Index page for account - it is restricted to ROLE_USER via security annotation
*
* @param UserInterface|null $user
* @return void
* @throws \Exception
* @Security("is_granted('ROLE_USER')")
*/
public function indexAction() {
$user = $this->getUser();
$this->view->user = $user;
if($user!=null && $user->getEmailConfirmed()){
$orderList = new Listing();
//list all confirmed orders of logged in user
$orderList->addConditionParam('originShop = ?', $_SERVER['HTTP_HOST'], 'AND');
$orderList->addConditionParam('customerEmail = ?', $user->getEmail(), 'AND');
$orderList->addConditionParam('orderState = ?', 'committed', 'AND');
$orderList->load();
}
else{
$this->addFlash('error', $this->get("translator")->trans("emailAdressNotConfirmedError"));
$customer = Customer::getByEmail($user->getEmail(), 1);
if($customer){
$token = $customer->getEmailConfirmToken();
$this->sendTokenMail($customer->getId(), $customer->getEmail(), $token, Site::getCurrentSite()->getRootPath().self::EMAIL_CUSTOMER_REGISTER);
$customer->save();
$this->addFlash('success', $this->get("translator")->trans("passwordResetEmailSent"));
}
}
$this->view->orders = $orderList;
}
/**
* @param Request $request
* @param UserInterface|null $user
* @return RedirectResponse
*/
public function confirmAction(Request $request, UserInterface $user = null) {
$this->view->user = $user;
$token = $request->get('token');
//check if user is confirming his token
if ($user!=null && $this->isGranted('ROLE_USER')) {
if($user->getEmailConfirmToken() == $token){
$user->setEmailConfirmed(true);
$user->save();
$this->addFlash('success', $this->get("translator")->trans("emailAddressConfirmedSuccess"));
}
else{
$this->addFlash('error', $this->get("translator")->trans("emailAdressConfirmedError").$token);
}
return $this->redirectToRoute('acc_index');
}
//check if user (not logged in) is confirming an email
$unloggedUser = Customer::getByEmailConfirmToken($token, 1);
if($unloggedUser){
$unloggedUser->setEmailConfirmed(true);
$unloggedUser->save();
$this->addFlash('success', $this->get("translator")->trans("emailAddressConfirmedSuccess"));
return $this->redirectToRoute('login');
}
$this->addFlash('error', $this->get("translator")->trans("emailAdressConfirmedError").$token);
return $this->redirectToRoute('login');
}
/**
* @param Request $request
* @return RedirectResponse
* @throws \Exception
*/
public function requestPasswordResetAction(Request $request){
//Form -> email, send email with token to that mail -> link to resetPasswordAction
$form = $this->createForm(RequestPasswordResetFormType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$customer = Customer::getByEmail($request->get('email'), 1);
if($customer){
$token = $this->generateToken();
$customer->setPwResetToken($token);
$customer->save();
$this->sendTokenMail($customer->getId(), $customer->getEmail(), $token, Site::getCurrentSite()->getRootPath().self::EMAIL_CUSTOMER_PW_RESET);
$this->addFlash('success', $this->get("translator")->trans("passwordResetEmailSent"));
return $this->redirectToRoute('login', ['reset' => 1]);
}
}
$this->view->form = $form->createView();
}
/**
* @param Request $request
* @return RedirectResponse
*/
public function resetPasswordAction(Request $request){
$customer = Customer::getByEmail($request->get('email'), 1);
//Check if token matches customer -> provide form to reset PW
if($customer && $request->get('token') == $customer->getPwResetToken()){
$form = $this->createForm(ResetPasswordFormType::class);
$form->handleRequest($request);
$this->view->form = $form->createView();
if ($form->isSubmitted() && $form->isValid()) {
$customer->setPassword($request->get('password')['first']);
$customer->setPwResetToken('');
$customer->save();
$this->addFlash('success', $this->get("translator")->trans("passwordResetSuccessfully"));
return $this->redirectToRoute('login', ['success' => 1]);
}
}
else{
$this->addFlash('error', $this->get("translator")->trans("passwordResetLinkNoLongerValid"));
return $this->redirectToRoute('login');
}
}
/**
* @param Int $customerId
* @param String $email
* @param String $token
* @param String $template
*/
protected function sendTokenMail(Int $customerId, String $email, String $token, String $template)
{
$customer = Customer::getById($customerId);
$params = [];
$params['token'] = $token;
$params['customer'] = $customer;
$params['email'] = $email;
$emailDoc = Document::getByPath($template);
$mail = new Mail(['document' => $emailDoc, 'params' => $params]);
$mail->setParams($params);
$mail->addTo($email);
$mail->send();
}
/**
* @return string
* @throws \Exception
*/
protected function generateToken(){
return bin2hex(random_bytes(self::TOKEN_DIGIT_SIZE));
}
}