'Route parameter only works for one code Zend Framework 2

I'm trying to have a verification process after registration (by a randomly generated verification code), but after I verify one code, it will not verify another one even though I am using the code that is stored in the database upon registration. For instance:

verify/c42557235936ed755d3305e2f7305aa3 

...works fine, but when I try and use another code (like /verify/3bc056ff48fec352702652cfa4850ac4), it generates the default layout for the application and does nothing. I don't know what is causing it.

Here is the code I have for this:

VerifyController -

namespace Application\Controller;

use Zend\Mvc\Controller\AbstractActionController;


class VerifyController extends AbstractActionController
{
    public $verify;


    public function indexAction()
    {
        $code = $this->params()->fromRoute('code');

        if ($this->getVerifyInstance()->authenticateCode($code) !== false) {
            $this->flashMessenger()->addSuccessMessage("Verification Successful, you can now login.");

            return $this->redirect()->toRoute('verify', array('action' => 'success'));
        } else {
            $this->flashMessenger()->addErrorMessage("Oops! Something went wrong while attempting to verify your account, please try again.");

            return $this->redirect()->toRoute('verify', array('action' => 'failure'));
        }
    }


    public function successAction()
    {

    }

    public function failureAction()
    {

    }


    public function getVerifyInstance()
    {
        if (!$this->verify) {
            $sm = $this->getServiceLocator();
            $this->verify = $sm->get('Application\Model\VerifyModel');
        }

        return $this->verify;
    }
}

VerifyModel -

namespace Application\Model;


use Zend\Db\TableGateway\TableGateway;
use Zend\Db\Sql\Sql;
use Zend\Db\Sql\Insert;
use Zend\Db\Adapter\Adapter;


class VerifyModel
{
    /**
     * @var TableGateway
     */
    protected $table_gateway;


    /**
     * @var mixed
     */
    protected $code;


    /**
     * Constructor method for VerifyModel class
     * @param TableGateway $gateway
     */
    public function __construct(TableGateway $gateway)
    {
        // check if $gateway was passed an instance of TableGateway
        // if so, assign $this->table_gateway the value of $gateway
        // if not, make it null
        $gateway instanceof TableGateway ? $this->table_gateway = $gateway : $this->table_gateway = null;
    }


    public function authenticateCode($code)
    {

        // authenticate the verification code in the url against the one in the pending_users table
        $this->code = !empty($code) ? $code : null;

        $select = $this->table_gateway->select(array('pending_code' => $this->code));

        $row = $select->current();

        if (!$row) {
            throw new \RuntimeException(sprintf('Invalid registration code %s', $this->code));
        } else {
            // verification code was found
            // proceed to remove the user from the pending_users table
            // and insert into the members table
            $data = array(
                'username' => $row['username'],
                'password' => $row['password'],
            );

            $sql = new Sql($this->table_gateway->getAdapter());

            $adapter = $this->table_gateway->getAdapter();

            $insert = new Insert('members');

            $insert->columns(array(
                'username',
                'password'
            ))->values(array(
                'username' => $data['username'],
                'password' => $data['password'],
            ));

            $execute = $adapter->query(
                $sql->buildSqlString($insert),
                Adapter::QUERY_MODE_EXECUTE
            );


            if (count($execute) > 0) {
                // remove the entry now
                $delete = $this->table_gateway->delete(array('pending_code' => $this->code));

                if ($delete > 0) {
                    return true;
                }
            }
        }
    }
}

the route:

'verify' => array(
   'type'    => 'Segment',
   'options' => array(
       'route' => 'verify/:code',
       'constraints' => array(
           'code'   => '[a-zA-Z][a-zA-Z0-9_-]*',
       ),

       'defaults' => array(
           'controller' => 'Application\Controller\Verify',
           'action'     => 'index',
       ),
    ),
 ),

and the layout configurer in Module.php:

public function init(ModuleManager $manager)
{
    $events = $manager->getEventManager();

    $shared_events = $events->getSharedManager();

    $shared_events->attach(__NAMESPACE__, 'dispatch', function ($e) {
        $controller = $e->getTarget();

        if (get_class($controller) == 'Application\Controller\SetupController') {
            $controller->layout('layout/setup');
        } else if (get_class($controller) == 'Application\Controller\MemberLoginController' || get_class($controller) == 'Application\Controller\AdminLoginController') {
            $controller->layout('layout/login');
        } else if (get_class($controller) == 'Application\Controller\RegisterController') {
            $controller->layout('layout/register');
        } else if (get_class($controller) == 'Application\Controller\VerifyController') {
            $controller->layout('layout/verify');
        }
    }, 100);
}


Solution 1:[1]

Your route is defined

'options' => array(
       'route' => 'verify/:code',
       'constraints' => array(
           'code'   => '[a-zA-Z][a-zA-Z0-9_-]*',
       ),

So, it should start with a letter (upper or lower case), and be followed by any (even none) number of characters (letters, numbers, underscores, and dashes).

So, valid routes:

verify/c42557235936ed755d3305e2f7305aa3 (the one you where trying)

verify/abcde

verify/N123-123

verify/Z

verify/X-1

etc.

Any of those should work. But the other code you provide in your question:

/verify/3bc056ff48fec352702652cfa4850ac4

starts with a number, so it wont be caught by your router. You need to either change how you generate your codes so they match your route, or change your route so it matches your codes. E.g.:

'options' => array(
       'route' => 'verify/:code',
       'constraints' => array(
       'code'   => '[a-zA-Z0-9][a-zA-Z0-9_-]{28,32}',
 ),

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Community