on Tutorials

Extending ZfcUser in Zend Framework 2

9 comments
Zend Framework 2 logo
Tweet about this on TwitterShare on FacebookShare on Google+Share on LinkedInShare on RedditShare on StumbleUpon

In the first part of Zend Framework 2 tutorial we learned how to install Zend Framework 2 and some crucial modules.

In this part we are going further and will show how to create new module and will be extending ZfcUser module’s views. We will just continue where we left off last time.

Creating Zend Framework 2 module

Zend Framework 2 uses a module system and you organize your 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).

What’s next?

In the next part, I will show you how to create actions for CRUD of Blog articles, how to protect them with ZfcUser and how to manage relations between User and Article entities. You can find the code on Github in Part2 branch.

Tweet about this on TwitterShare on FacebookShare on Google+Share on LinkedInShare on RedditShare on StumbleUpon



  • Ro

    just check source code at github and figured that new views must be placed in /module/Blog/view/zfc-user/user/ not in /module/Blog/src/view/zfc-user/user/ (as mantioned in tutorial)

    • http://codeforest.net Zvonko Biškup

      Nice, catch, I updated the tutorial

  • Ro

    Can’t wait for the next part

  • Timo

    thanks a alot.

  • Tom

    Hi Zvonko. Hey you found a solution to make the ZfcUser module support email validation process for new registering users?

  • Marius

    I would love to see the next parts.

    Great work!

  • Bas

    Overriding of View scripts seems dependent on the order of your modules in application.config.php. The module you want to override must be placed before the module that will override it.

    So make sure that in your application.config.php file you have the ZfcUser module placed before the blog module.

    / This should be an array of module namespaces used in the application.
    ‘modules’ => array(
    ‘Application’,
    ‘ZendDeveloperTools’,
    ‘DoctrineModule’,
    ‘DoctrineORMModule’,
    ‘ZfcBase’,
    ‘ZfcUser’,
    ‘ZfcUserDoctrineORM’,
    ‘Blog’,
    ),

  • Edgar

    How did you redirect the default page to the zend user module, that part i didn’t understamd

  • Eduard Luca

    This might seem natural to someone who’s familiar with ZF2 (and now after reading, it does to me too — the part about overriding the views from another module), but to us newbs, this is very helpful information.

    The only thing missing in this tutorial (maybe coming in the next parts) is how to override actual functionality (ie. the controller part and whatnot). For instance, I’d like to be able to add the “username” functionality, which I’ve seen ZfcUser is somewhat prepared for. Maybe you can incorporate that in one of your future tutorials.

    Anyways, keep them coming, they’re amazing. Already added this page to my bookmarks and will keep an eye on it :)