Welcome to Abdul Malik Ikhsan's Blog

Zend Framework 2 : Create Custom Toolbar for ZendDeveloperTools

Posted in Tutorial PHP, Zend Framework 2 by samsonasik on June 27, 2014

zf2-zendframework2

ZendDeveloperTools toolbars are great to help us debug our application. However, when we need to have additional toolbar that not yet in it, we need to add it by creating custom toolbar for it. Ok, for example, we want to add a session toolbar that read our current session Container key -> value like this :

session-toolbar-rev
To make it easy to learn, let’s apply it into new module, I created a new module for it named SanSessionToolbar like the following :
san-session-toolbar

1. Let’s start with the Collector :

namespace SanSessionToolbar\Collector;

use ZendDeveloperTools\Collector\CollectorInterface;
use Zend\Mvc\MvcEvent;
use Zend\Session\Container;

/**
 * Session Data Collector.
 */
class SessionCollector implements CollectorInterface
{
    /**
     * @inheritdoc
     */
    public function getName()
    {
         // this name must same with *collectors* name in the configuration
        return 'session.toolbar';
    }

    /**
     * {@inheritDoc}
     */
    public function getPriority()
    {
        return 10;
    }

    /**
     * @inheritdoc
     */
    public function collect(MvcEvent $mvcEvent)
    {
    }
    
    public function getSessionData()
    {
        $container = new Container;
        $arraysession = $container->getManager()->getStorage()->toArray();
        
        $data = array();
        foreach($arraysession as $key => $row) {
            if ($row instanceof \Zend\Stdlib\ArrayObject) {
                $iterator = $row->getIterator();
                while($iterator->valid()) {
                    $data[$iterator->key()] =  $iterator->current() ;
                    $iterator->next();
                }
            }
        }
        
        return $data;
    }
}

2. Now, create a view to var_dump the SanSessionToolbar\Collector\SessionCollector::getSessionData().

<?php /* @var $collector \SanSessionToolbar\Collector\SessionCollector */ ?>
<div class="zdt-toolbar-entry">
    <div class="zdt-toolbar-preview">
        <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAATxJREFUeNpi/P//PwMhMJuRkRVItQNxKhBzAPFOIM5O/f//MbpaFgbiAMigYiS+LxCDXOKPrpCJSAP1sYiZY1NIrIGHsYhtw6aQWC8vA2IlIM4EYn6oYRXYFDISEylokQOKlG/ACPlLsguBBggAKRUglgbi70B8EWjQS3x6sLoQaFAikLIDYjcglkKSegHEGUBDN+IyEFekeAOxJRBfAeJPSOISQDwZaKEYSS5Ec20KiEITVgW68g65yeYHAwmAGAN90PgPgPgjWQZCw8oOTXgX0LuvyXWhBxBLIvFBaW8zJV52RePfA+LdZBkI9K44kHJAEz4G9O5Pcl3IA8QyaGJHKYllRixiylDXywCxFKkGvgPiG2hiJUCDQHn5PhBbkGQgMKxABsYC8UEg/grFH4D4BBDHA/EebPoAAgwA3RZUHjvT8+IAAAAASUVORK5CYII=" alt="SESSION Data">
        <span class="zdt-toolbar-info">
                SessionData     
        </span>
    </div>
    <div class="zdt-toolbar-detail">
        <span class="zdt-toolbar-info zdt-toolbar-info-redundant">
            <span class="zdt-detail-label">Session Data</span>
        </span>
        <span class="zdt-toolbar-info">
            <span class="zdt-detail-pre">
                <?php Zend\Debug\Debug::dump($collector->getSessionData()); ?>
            </span>
        </span>
    </div>
</div> 

3. Great!, Let’s configure the module configuration ( config/module.config.php ), Remember, that the toolbar entries name must same with our SessionCollector::getName().

return array(
    
    'service_manager' => array(
        'invokables' => array(
            'session.toolbar' => 
                'SanSessionToolbar\Collector\SessionCollector',
        ),
    ),
    
    'view_manager' => array(
        'template_map' => array(
            'zend-developer-tools/toolbar/session-data'
                => __DIR__ . '/../view/zend-developer-tools/toolbar/session-data.phtml',
        ),
    ),
        
    'zenddevelopertools' => array(
        'profiler' => array(
            'collectors' => array(
                'session.toolbar' => 'session.toolbar',
            ),
        ),
        'toolbar' => array(
            'entries' => array(
                'session.toolbar' => 'zend-developer-tools/toolbar/session-data',
            ),
        ),
    ),
    
);

The ‘session.toolbar’ must be registered into ServiceManager with an instance of SanSessionToolbar\Collector\SessionCollector, and registered into ‘zenddevelopertools’ config profiler and toolbar.
4. The Module.php is a usual Module class.
5. Register your new module into config/application.config.php
6. Now, let’s test it by creating session data in our controller :

    public function indexAction()
    {
        $container = new \Zend\Session\Container;
        $container->a   = 'b';
        $container->foo = 'bar';
        
        return new ViewModel();
    }

Done ;). You can grab this module from my github account : https://github.com/samsonasik/SanSessionToolbar

Reference :
1. http://stackoverflow.com/questions/20325842/how-to-log-something-to-zend-developer-tools-toolbar
2. Image session icon originally from : http://makemore.info.yorku.ca/files/2012/11/info.png, encoded with base64_encode.

Zend Framework 2 : Disable some toolbar entries from ZendDeveloperTools

Posted in Tutorial PHP, Zend Framework 2 by samsonasik on June 26, 2014

zf2-zendframework2Sometime, when we are working with modules that provide a new toolbar entries, then we no need to keep the default ZendDeveloperTools toolbar entries because it replaced by new toolbar entries. For example, we are working with Doctrine and we use DoctrineORMModule,  we automatically get the toolbar like this :
zdt-toolbar-db-doctrine
What if we need to eliminate the Zend\Db toolbar entry from the toolbar ? Let’s take a look at ZendDeveloperTools Options for it one by one method to know what’s going on :
1. Take a look at ZendDeveloperTools\Options $toolbar property :

namespace ZendDeveloperTools;

use Zend\Stdlib\AbstractOptions;

class Options extends AbstractOptions
{
    /*** Other properties here ***/
    /**
     * @var array
     */
    protected $toolbar = array(
        'enabled'       => false,
        'auto_hide'     => false,
        'position'      => 'bottom',
        'version_check' => false,
        'entries'       => array(
            'request' => 'zend-developer-tools/toolbar/request',
            'time'    => 'zend-developer-tools/toolbar/time',
            'memory'  => 'zend-developer-tools/toolbar/memory',
            'config'  => 'zend-developer-tools/toolbar/config',
            'db'      => 'zend-developer-tools/toolbar/db',
        ),
    );
    
    /*** Options methods here ***/
}

Now, we know that the toolbar entry for Zend\Db is the entries with key ‘db’.
2. There is a method to setToolbar with its logic

namespace ZendDeveloperTools;

use Zend\Stdlib\AbstractOptions;

class Options extends AbstractOptions
{
    /*** Options properties here ***/
    
    /**
     * Sets Toolbar options.
     *
     * @param array $options
     */
    public function setToolbar(array $options)
    {
        /*** other logic here ***/ 
        if (isset($options['entries'])) {
            if (is_array($options['entries'])) {
                foreach ($options['entries'] as $collector => $template) {
                    if ($template === false || $template === null) {
                        unset($this->toolbar['entries'][$collector]);
                    } else {
                        $this->toolbar['entries'][$collector] = $template;
                    }
                }
            }
            /*** other logic here ***/
        }
    }
    
    /*** other Options methods here ***/
}

Now, we know, to unset the entries, we need to make the ‘value’ of its key false or null.
3. Last step, setting up the config/autoload/zenddevelopertools.local.php :

return array(
    'zenddevelopertools' => array(
         'profiler' => array( /** other config here **/ ),
         'events' => array( /** other config here **/ ),
         'toolbar' => array(
               /** other config here **/
               'entries' => array(
                   'db' => false,
               )
          ),
    ),
);

Done, now, our ZendDeveloperTools toolbar will look like this :
zdt-toolbar-doctrine-only-without-zend-db

Zend Framework 2 : Using Custom Authentication condition with DoctrineModule

Posted in Tutorial PHP, Zend Framework 2 by samsonasik on June 21, 2014

zf2-zendframework2In DoctrineModule, there is a way to use authentication functionality that call specific entity and its properties with identity and credential. What if we need to use custom authentication conditional, like when user has is_active = 1 or is_enabled = 1. For example, we have a table structure like the following :

CREATE TABLE IF NOT EXISTS `User` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `email` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `password` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `is_active` smallint(6) NOT NULL DEFAULT '1',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1;

There is a is_active field that need to be checked when authentication process excecuted. What we need to do, is to create a custom Authentication adapter objectrepository that extends DoctrineModule\Authentication\Adapter\ObjectRepository :

namespace MyDoctrineAuth\Adapter;
 
use DoctrineModule\Authentication\Adapter\ObjectRepository as BaseObjectRepository;
use Zend\Authentication\Result as AuthenticationResult;

class ObjectRepository extends BaseObjectRepository
{
    /**
     * {@inheritDoc}
     */
    public function authenticate()
    {
        $this->setup();
        $options  = $this->options;
        $identity = $options
            ->getObjectRepository()
            ->findOneBy(array(
                $options->getIdentityProperty() => $this->identity,
                // with assumption, our entity use $isActive property
                'isActive' => 1,  
            ));

        if (!$identity) {
            $this->authenticationResultInfo['code'] = AuthenticationResult::FAILURE_IDENTITY_NOT_FOUND;
            $this->authenticationResultInfo['messages'][] = 'A record with the supplied identity could not be found.';

            return $this->createAuthenticationResult();
        }

        $authResult = $this->validateIdentity($identity);

        return $authResult;
    }
}

The custom ObjectRepository above override the authenticate() method with adding more condition into findOneBy method.
Now, we need to create a factory to instantiate its class :

namespace MyDoctrineAuth\Factory\Authentication;

use DoctrineModule\Service\Authentication\AdapterFactory as BaseAdapterFactory;

use MyDoctrineAuth\Adapter\ObjectRepository;
use Zend\ServiceManager\ServiceLocatorInterface;

class AdapterFactory extends BaseAdapterFactory
{
    /**
     * {@inheritDoc}
     *
     * @return \MyDoctrineAuth\Adapter\ObjectRepository
     */
    public function createService(ServiceLocatorInterface $serviceLocator)
    {
        /* @var $options \DoctrineModule\Options\Authentication */
        $options = $this->getOptions($serviceLocator, 'authentication');

        if (is_string($objectManager = $options->getObjectManager())) {
            $options->setObjectManager($serviceLocator->get($objectManager));
        }

        return new ObjectRepository($options);
    }
}

Great!, time to register the AdapterFactory into module.config.php :

return array(
    'doctrine_factories' => array(
        'authenticationadapter' => 'MyDoctrineAuth\Factory\Authentication\AdapterFactory',
    ),
),

You can grab sample of above code here : https://github.com/samsonasik/MyDoctrineAuth .