May 21, 2014

May 21, 2014
In this article, we are going to discuss about How to extend the ZfcUser module in Zend Framework 2. ZfcUser is a user registration and authentication module for Zend Framework 2. Out of the box, ZfcUser works with Zend\Db, however alternative storage adapter modules are available (see below). ZfcUser provides the foundations for adding user authentication and registration to your ZF2 site. It is designed to be very simple and easily to extend.

Creating Zend Framework 2 module

Zend Framework 2 uses a module system and we can organize our main application-specific code within each module.

The module system in ZF2 has been designed to be a generic and powerful foundation from which developers and other projects can build their own module or plugin systems.

The easiest way to create a new module is by using ZFTool. I think the easiest way to install it is to use a .phar file from that site and just pur it in your /vendor folder inside your project directory.

After you downloaded/installed ZFTool, run this in your console (I ran it inside vendor directory, if you are running from somewhere else, be sure to adjust the last parameter which is path to your project directory):

zftool.phar create module Blog ./

This will create a module called Blog with all the necessary folders and files needed for a module to function. It will also add your newly created module to modules array in your application.config.php file.

If you go to zf2blog.home/blog now, you will get an 404 error, which is fine as we don't have a controller and views for our module yet.

So, let's first adjust that, open /module/Blog/config/module.config.php and make it look like this:

return array(
        'controllers' => array(
                'invokables' => array(
                        'Blog\Controller\Blog' => 'Blog\Controller\BlogController'
                ),
        ),
        'view_manager' => array(
                'template_path_stack' => array(
                        'blog' => __DIR__ . '/../view',
                ),
        ),
);

Preparing Blog module

Let's prepare Blog module for further work. We will first add some routes to our module config file:

/module/Blog/config/module.config.php

...
// Routes
        'router' => array(
                'routes' => array(
                        'blog' => array(
                                'type'    => 'segment',
                                'options' => array(
                                        'route'    => '/blog[/:action][/:id]',
                                        'constraints' => array(
                                                'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
                                                'id'     => '[0-9]+',
                                        ),
                                        'defaults' => array(
                                                'controller' => 'Blog\Controller\Blog',
                                                'action'     => 'index',
                                        ),
                                ),
                        ),
                ),
        ),

...

Now, we need a Blog Controller and it's index Action and index view, so create


/module/Blog/src/Controller/BlogController.php

<?php
namespace Blog\Controller;

use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;

class BlogController extends AbstractActionController
{
    /**
     * (non-PHPdoc)
     * @see \Zend\Mvc\Controller\AbstractActionController::indexAction()
     */
    public function indexAction()
    {
        return new ViewModel();
    }

}

and also create the view:


/module/Blog/view/blog/blog/index.phtml

<div class="page-header">
    <h1><?php echo $this->translate('Blog'); ?></h1>

</div>

That's it, if you point your browser to zf2blog.home/blog, you will see that it works.

Extending ZfcUser views

Let us now adjust ZfcUser views to Twitter Bootstrap 3 which is used in Zend Skeleton application we used. To override ZfcUser module's views, we just need to create a proper folders in our module's views folder and put the ZfcUser views we wish to override inside.

So create /module/Blog/view/zfc-user/user folder and add following files to it:

/module/Blog/view/zfc-user/user/register.phtml:

<div class="page-header">
    <h1><?php echo $this->translate('Register'); ?></h1>
</div>

<?php
if (!$this->enableRegistration) {
    print "Registration is disabled";
    return;
}
$form = $this->registerForm;
$form->prepare();
$form->setAttribute('action', $this->url('zfcuser/register'));
$form->setAttribute('method', 'post');
echo $this->form()->openTag($form);
?>

<?php foreach ($form as $element) : ?>

    <div style="width: 330px;" class="form-group <?php if ($this->formElementErrors($element)) echo "has-error" ?>">
        <?php
            if ('submit' != $element->getAttribute('type')) { ?>
                <label class="control-label"><?php echo $element->getLabel() ?></label>
                <?php
                $element->setAttribute('class', 'form-control')
                        ->setAttribute('placeholder', $element->getLabel());
            } else {
                $element->setAttribute('class', 'btn btn-success');
            }
            if ($element instanceof Zend\Form\Element\Captcha) {
                echo $this->formCaptcha($element);
            } else {
                echo $this->formElement($element);
            }
            if ($this->formElementErrors($element)) : ?>
                <?php
                echo $this->formElementErrors()
                    ->setMessageOpenFormat('<p class="help-block">')
                    ->setMessageSeparatorString('</p><p class="help-block">')
                    ->setMessageCloseString('</p>')
                    ->render($element);
                ?>
            <?php endif; ?>
    </div>

<?php
endforeach;
    if ($this->redirect): ?>
        <input type="hidden" name="redirect" value="<?php echo $this->escapeHtml($this->redirect) ?>" />
    <?php endif ?>

<?php echo $this->form()->closeTag() ?>

/module/Blog/view/zfc-user/user/login.phtml:

<div class="page-header">
    <h1><?php echo $this->translate('Sign in'); ?></h1>
</div>

<?php
$form = $this->loginForm;
$form->prepare();
$form->setAttribute('action', $this->url('zfcuser/login'));
$form->setAttribute('method', 'post');
?>

<?php echo $this->form()->openTag($form) ?>
<?php foreach ($form as $element) : ?>

    <div style="width: 330px;" class="form-group <?php if ($this->formElementErrors($element)) echo "has-error" ?>">
        <?php
            if ('submit' != $element->getAttribute('type')) { ?>
                <label class="control-label"><?php echo $element->getLabel() ?></label>
                <?php
                $element->setAttribute('class', 'form-control')
                        ->setAttribute('placeholder', $element->getLabel());
            } else {
                $element->setAttribute('class', 'btn btn-success');
            }
            echo $this->formElement($element);
            if ($this->formElementErrors($element)) : ?>
                <?php
                echo $this->formElementErrors()
                    ->setMessageOpenFormat('<p class="help-block">')
                    ->setMessageSeparatorString('</p><p class="help-block">')
                    ->setMessageCloseString('</p>')
                    ->render($element);
                ?>
            <?php endif; ?>
    </div>

<?php
endforeach;

echo $this->form()->closeTag() ?>

<?php if ($this->enableRegistration) : ?>
<?php echo $this->translate('Not registered?'); ?> <a href="<?php echo $this->url('zfcuser/register') . ($this->redirect ? '?redirect='.$this->redirect : '') ?>"><?php echo $this->translate('Sign up!'); ?></a>

<?php endif; ?>

/module/Blog/view/zfc-user/user/index.phtml:

<div class="page-header">
    <h1><?php echo $this->translate('User details'); ?></h1>
</div>
<div class="container">
<div class="row">
<div style="float:left; padding-right:16px;"><?php echo $this->gravatar($this->zfcUserIdentity()->getEmail()) ?></div>
<h3><?php echo $this->translate('Hello'); ?>, <?php echo $this->zfcUserDisplayName() ?>!</h3>
<a href="<?php echo $this->url('zfcuser/logout') ?>">[<?php echo $this->translate('Sign Out'); ?>]</a>
</div>
</div>

/module/Blog/view/zfc-user/user/changepassword.phtml:

<?php echo $this->form()->closeTag(); ?>
<div class="page-header">
    <h1><?php echo sprintf($this->translate('Change Password for %s'), $this->zfcUserDisplayName()); ?></h1>
</div>
<?php if ($status === true) : ?>
<div class="alert alert-success"><?php echo $this->translate('Password changed successfully.');?></div>
<?php elseif ($status === false) : ?>
<div class="alert alert-danger"><?php echo $this->translate('Unable to update your password. Please try again.'); ?></div>
<?php endif; ?>
<?php
    $form = $this->changePasswordForm;

    $form->prepare();
    $form->setAttribute('action', $this->url('zfcuser/changepassword'));
    $form->setAttribute('method', 'post');

    $emailElement = $form->get('identity');
    $emailElement->setValue($this->zfcUserIdentity()->getEmail());

    echo $this->form()->openTag($form);
?>

<?php foreach ($form as $element) : ?>

    <div style="width: 330px;" class="form-group <?php if ($this->formElementErrors($element)) echo "has-error" ?>">
        <?php
            if ('submit' != $element->getAttribute('type')) { ?>
                <label class="control-label"><?php echo $element->getLabel() ?></label>
                <?php
                $element->setAttribute('class', 'form-control')
                        ->setAttribute('placeholder', $element->getLabel());
            } else {
                $element->setAttribute('class', 'btn btn-success');
            }
            if ($element instanceof Zend\Form\Element\Captcha) {
                echo $this->formCaptcha($element);
            } else {
                echo $this->formElement($element);
            }
            if ($this->formElementErrors($element)) : ?>
                <?php
                echo $this->formElementErrors()
                    ->setMessageOpenFormat('<p class="help-block">')
                    ->setMessageSeparatorString('</p><p class="help-block">')
                    ->setMessageCloseString('</p>')
                    ->render($element);
                ?>
            <?php endif; ?>
    </div>

<?php
endforeach;?>
<?php if ($this->redirect): ?>
        <input type="hidden" name="redirect" value="<?php echo $this->escapeHtml($this->redirect) ?>" />
    <?php endif ?>
<?php echo $this->form()->closeTag() ?>

/module/Blog/view/zfc-user/user/changeemail.phtml:

<div class="page-header">
    <h1><?php echo sprintf($this->translate('Change Email for %s'), $this->zfcUserDisplayName()); ?></h1>
</div>
<?php if ($status === true) : ?>
<div class="alert alert-success"><?php echo $this->translate('Email address changed successfully.'); ?></div>
<?php elseif ($status === false) : ?>
<div class="alert alert-danger"><?php echo $this->translate('Unable to update your email address. Please try again.'); ?></div>
<?php endif; ?>
<?php
    $form = $this->changeEmailForm;

    $form->prepare();
    $form->setAttribute('action', $this->url('zfcuser/changeemail'));
    $form->setAttribute('method', 'post');
    echo $this->form()->openTag($form);
?>

<?php foreach ($form as $element) : ?>

    <div style="width: 330px;" class="form-group <?php if ($this->formElementErrors($element)) echo "has-error" ?>">
        <?php
            if ('submit' != $element->getAttribute('type')) { ?>
                <label class="control-label"><?php echo $element->getLabel() ?></label>
                <?php
                $element->setAttribute('class', 'form-control')
                        ->setAttribute('placeholder', $element->getLabel());
            } else {
                $element->setAttribute('class', 'btn btn-success');
            }
            if ($element instanceof Zend\Form\Element\Captcha) {
                echo $this->formCaptcha($element);
            } else {
                echo $this->formElement($element);
            }
            if ($this->formElementErrors($element)) : ?>
                <?php
                echo $this->formElementErrors()
                    ->setMessageOpenFormat('<p class="help-block">')
                    ->setMessageSeparatorString('</p><p class="help-block">')
                    ->setMessageCloseString('</p>')
                    ->render($element);
                ?>
            <?php endif; ?>
    </div>

<?php
endforeach;?>
<input class="btn btn-success" type="submit" value="Submit" />
<?php if ($this->redirect): ?>
        <input type="hidden" name="redirect" value="<?php echo $this->escapeHtml($this->redirect) ?>" />
    <?php endif ?>
<?php echo $this->form()->closeTag() ?>


This code is adjusting ZfcUser forms to Twitter Bootstrap markup. If you now go to zf2blog.home/user/register, you will see that the form looks awesome now. Even the validation messages looks better (try to submit the register form without entering the username).

0 comments:

Post a Comment