2
\$\begingroup\$

I know I should use services and patterns to refactor this controller action, but I can't imagine one that could fit/be appropriate for this problem.

It seems a strategy or template, but a strategy is supposed to be changed if needed; in my case, it should be always the same:

  1. Get the customer
    1. If doesn't exist store the error key (and dispatch/redirect)
    2. Otherwise continue
  2. Get current agent permission
    1. If special privileges, just continue
    2. Otherwise, check customer agent against current logged agent. In case of error, store the errore key (and dispatch/redirect)
  3. Check if customer is enabled, otherwise store the error key (and dispatch/redirect)
  4. Get customer users
    1. If there are no users, store the error key (and dispatch/redirect)
    2. Otherwise continue
  5. Pick the first user and check his privileges
    1. In case of errors, store the error key (and dispatch/redirect)
    2. Success, redirect

Actual code:

public function impersonateAction($id, Request $request)
{
    $referer = $this->redirect($request->headers->get('referer'));

    /** @var \CommonBundle\Model\CustomerInterface $customer */
    $customer = $this->get('common.repository.customer')
        ->find($id);

    /** @var \Symfony\Component\EventDispatcher\EventDispatcherInterface $dispatcher */
    $dispatcher = $this->get('event_dispatcher');

    $error = false;

    // Customer doesn't exist
    if (!$error && empty($customer)) {
        $error = Impersonate::CUSTOMER_NOT_FOUND_ERROR;
    }

    // Check current agent privileges
    if (!$error && !$this->isGranted(AgentInterface::ROLE_SUPER_AGENT)
        && $customer->getAgent() !== $this->getUser()) {
        $error = Impersonate::DENIED_ERROR;
    }

    // Customer is disabled
    if (!$error && !$customer->isEnabled()) {
        $error = Impersonate::CUSTOMER_DISABLED_ERRROR;
    }

    // There are no users for this customer
    /** @var \CommonBundle\Entity\Repository\UserRepositoryInterface $repository */
    $repository = $this->get('common.repository.user');
    if (!$error && !($users = $repository->findByCustomer($customer))) {
        $error = Impersonate::NO_USERS_ERROR;
    }

    // We have a candidate, forward the check to Symfony user checker
    if (!$error) {
        try {
            $this->get('security.user_checker')->checkPreAuth(current($users));
        } catch (\Exception $e) {
            $error = Impersonate::USER_UNKOWN_ERROR;

            if ($e instanceof LockedException) {
                $error = Impersonate::USER_LOCKED_ERROR;
            }

            if ($e instanceof DisabledException) {
                $error = Impersonate::USER_DISABLED_ERROR;
            }

            if ($e instanceof AccountExpiredException) {
                $error = Impersonate::USER_ACCOUNT_EXPIRED;
            }
        }
    }

    // Dispatch the error and redirect to referer
    if ($error) {
        $dispatcher->dispatch(
            AgentEvents::CUSTOMER_IMPERSONATE_ERROR,
            new ImpersonateEvent($this->trans($error))
        );
    }

    // Success
    $this->loginUser(
        $user,
        $this->container->getParameter('agent.impersonate.firewall_name')
    );

    return $this->redirect($this->generateUrl(
        $this->container->getParameter('agent.impersonate.target_path')
    ));
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.