Welcome to Abdul Malik Ikhsan's Blog

Zend Framework 2 : Using Doctrine Extension with DoctrineModule and DoctrineORMModule

Posted in Tutorial PHP, Zend Framework 2 by samsonasik on October 15, 2014

zf2-zendframework2 In ZF2, by using DoctrineModule, we can manage the extension that implements Doctrine\Common\EventSubscriber in configuration. For example, we have TablePrefix subcsriber to set table prefix query result like the following :

namespace Application\DoctrineExtension;

use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
use Doctrine\Common\EventSubscriber;

class TablePrefix implements EventSubscriber
{
    protected $prefix = '';

    public function __construct($prefix)
    {
        $this->prefix = (string) $prefix;
    }
    
    public function getSubscribedEvents()
    {
        return ['loadClassMetadata'];
    }

    public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs)
    {
        $classMetadata = $eventArgs->getClassMetadata();
        $classMetadata->setTableName($this->prefix . $classMetadata->getTableName());
        foreach ($classMetadata->getAssociationMappings() as $fieldName => $mapping) {
            if ($mapping['type'] == \Doctrine\ORM\Mapping\ClassMetadataInfo::MANY_TO_MANY) {
                $mappedTableName = $classMetadata->associationMappings[$fieldName]['joinTable']['name'];
                $classMetadata->associationMappings[$fieldName]['joinTable']['name'] = $this->prefix . $mappedTableName;
            }
        }
    }
}

Because above class need a dependency at __construct part, we need to build the instance via service manager factory :


use Application\DoctrineExtension\TablePrefix;

return [
   'service_manager' => [
        'factories' => [
            'tablePrefix' => function($sm) {
                // for cache-able config, use factory instead!
                return new TablePrefix('app.');                                      
            },
        ],
   ],
   //...
];

And now, we can register to the ‘subscribers’ key under ‘orm_default’ ( if we use ‘orm_default’ as connection ).

return [
   // ...
   'doctrine' => [
        // ... common doctrine driver config here

        'eventmanager' => [
            'orm_default' => [
                'subscribers' => [
                    'tablePrefixService',
                ],
            ],
        ],
        // ...
    ],       
   //...
];

And when we call it :

$albumQb = $this->getServiceLocator()
   ->get('Doctrine\ORM\EntityManager')->getRepository('Application\Entity\Album')
   ->createQueryBuilder('a');
echo $albumQb->getQuery()->getSql();

It will produce :

SELECT a0_.id AS id0, a0_.artist AS artist1, a0_.title AS title2 FROM app.album a0_

Now… What if the Extension doesn’t extends the Doctrine\Common\EventSubscriber ?

We need to register it in the EventManager of Doctrine Connection as new event listener with utilize DoctrineORMModule, so we have to override the DoctrineORMModule\Service\EntityManagerFactory :

namespace Application\Factory\Service;

use DoctrineORMModule\Service\EntityManagerFactory as BaseEntityManagerFactory;
use Doctrine\ORM\EntityManager;
use DoctrineModule\Service\AbstractFactory;
use Zend\ServiceManager\ServiceLocatorInterface;

class EntityManagerFactory extends BaseEntityManagerFactory
{
    /**
     * {@inheritDoc}
     * @return EntityManager
     */
    public function createService(ServiceLocatorInterface $sl)
    {
        /* @var $options \DoctrineORMModule\Options\EntityManager */
        $options    = $this->getOptions($sl, 'entitymanager');
        $connection = $sl->get($options->getConnection());
        $config     = $sl->get($options->getConfiguration());

        $sl->get($options->getEntityResolver());
        
        // add Table Prefix
        $evm = $connection->getEventManager();
        // assumed 'tablePrefixService' already registered in service_manager before... 
        $evm->addEventListener(\Doctrine\ORM\Events::loadClassMetadata, $sl->get('tablePrefixService'));

        return EntityManager::create($connection, $config, $evm);
    }
}

Now, we override the ‘doctrine_factories’ config in our config :

return [
    'doctrine' => [
        // ... common doctrine driver config here 
    ],
    
    'doctrine_factories' => [
        'entitymanager' => 'Application\Factory\Service\EntityManagerFactory',
    ],
];

To make it works, The "doctrine_factories" override config need to be placed after the doctrine config.

That’s it. I hope it useful ;)

References :
1. http://marco-pivetta.com/doctrine-orm-zf2-tutorial/
2. http://stackoverflow.com/questions/12841102/how-to-configure-doctrine-extensions-in-zend-framework-2
3. https://gist.github.com/samsonasik/90f041f049d509161d61
4. https://github.com/doctrine/DoctrineModule
5. https://github.com/doctrine/DoctrineORMModule

Zend Framework 2 : Build application Using PHP 5.4 – 5.6 Features

Posted in Tutorial PHP, Zend Framework 2 by samsonasik on October 12, 2014

zf2-zendframework2Zend Framework 2 ( 2.3.3 ) requires PHP 5.3.23 or above. If we use PHP 5.4 or above, we can use their features when building module(s). There are many feature, I will only show you some of them that are useful.

1. PHP 5.4 features

a. Traits
ZF2 have several component that provide traits that ready to be used in our application. For example : Zend\EventManager\EventManagerAwareTrait. Instead of implements Zend\EventManager\EventManagerInterface, we can just use this traits.
This is the old way :

namespace Sample\Model;

use Zend\EventManager\EventManager;
use Zend\EventManager\EventManagerAwareInterface;
use Zend\EventManager\EventManagerInterface;

class Foo implements EventManagerAwareInterface
{
    protected $events;
    
    public function setEventManager(EventManagerInterface $events)
    {
        $this->events = $events;
        return $this;
    }
    
    public function getEventManager()
    {
        if (!$this->events) {
            $this->setEventManager(new EventManager(__CLASS__));
        }
        
        return $this->events;
    }
    
    public function bar($baz, $bat = null)
    {
        $params = compact('baz', 'bat');
        $this->getEventManager()->trigger(__FUNCTION__, $this, $params);
    }
}

This is the new way :

namespace Sample\Model;

use Zend\EventManager\EventManagerAwareTrait;

class Foo
{
    use EventManagerAwareTrait;
    
    public function bar($baz, $bat = null)
    {
        $params = compact('baz', 'bat');
        $this->getEventManager()->trigger(__FUNCTION__, $this, $params);
    }
}

Why not extends ? Because extends feature can already been used, and we need another things to be used, for example in the form class that already extends Zend\Form.
We can use many trait in one class.

b. Short array syntax
This is my favourite feature from PHP 5.4 that change array() to []. Lesser code that well be used.
This is the old way :

return array(    
    'router' => array(
        'routes' => array(
           'home' => array(
                'type' => 'Zend\Mvc\Router\Http\Literal',
                'options' => array(
                    'route'    => '/',
                    'defaults' => array(
                        'controller' => 'Application\Controller\Index',
                        'action'     => 'index',
                    ),
                ),
            ),
        ),
    ),
    // ... 
);

This is the new way :

return [
    'router' => [
        'routes' => [
            'home' => [
                'type' => 'Zend\Mvc\Router\Http\Literal',
                'options' => [
                    'route'    => '/',
                    'defaults' => [
                        'controller' => 'Application\Controller\Index',
                        'action'     => 'index',
                    ],
                ],
            ],
        ],
    ],
    // ...
];

You don’t want to manually change existing project ? You can use this tool to convert everything : https://github.com/thomasbachem/php-short-array-syntax-converter .

c. array dereferencing
In old way, when you want to access value of array from function that return array, you need to make it variable first.
For example, when you want to use one of config file.
This is the old way :

$config = $this->getServiceLocator()->get('Config');
echo $config['myconfig'];

This is the new way :

$myconfig = $this->getServiceLocator()->get('Config')['myconfig'];

d. Closures now support $this.
This is the old way : ( grabbed from https://mwop.net/blog/2012-07-30-the-new-init.html )

public function setEventManager(EventManagerInterface $events)
{
    parent::setEventManager($events);
    $controller =  $this;
    
    $events->attach('dispatch', function ($e) use ($controller) {
        $request = $e->getRequest();
        $method = $request->getMethod();
        
        if (!in_array($method, array('PUT', 'DELETE', 'PATCH'))) {
            // nothing to do
            return;
        }
        
        if ($controller->params()->fromRoute('id', false)) {
            // nothing to do
            return;
        }
        
        // Missing identifier! Redirect.
        return $controller->redirect()->toRoute(/* ... */);
    }, 100); // execute before executing action logic
}

This is the new way :
Now, we don’t need to pass $this that assigned to variable anymore, just use it inside the closure.

public function setEventManager(EventManagerInterface $events)
{
    parent::setEventManager($events);
    
    $events->attach('dispatch', function ($e)  {
        $request = $e->getRequest();
        $method = $request->getMethod();
        
        if (!in_array($method, ['PUT', 'DELETE', 'PATCH'])) {
            // nothing to do
            return;
        }
        
        if ($this->params()->fromRoute('id', false)) {
            // nothing to do
            return;
        }
        
        // Missing identifier! Redirect.
        return $this->redirect()->toRoute(/* ... */);
    }, 100); // execute before executing action logic
}

e. Class member access on instantiation has been added
This is the old way :

use Zend\Db\TableGateway\TableGateway;
$selectedtable = new TableGateway('tableneedtobeselected', $adapterSelect);
$select = $selectedtable->getSql()->select()->where(array('field' => 'value'));

This is the new way :

use Zend\Db\TableGateway\TableGateway;
$select = (new TableGateway('tableneedtobeselected', $adapterSelect))
    ->getSql()->select()->where(['field' => 'value']);

2. PHP 5.5 features

a. Class name resolution via ::class
It is very useful when we call service that has name same as its Namespace\ClassName.
This is the old way :

$serviceLocator->get('My\Very\Long\Service\Name');

This is the new way :

use My\Very\Long\Service\Name;
$serviceLocator->get(Name::class);

It will reduce of re-type long servicename when the service call many times in our file, for example : in tests file. It will be useful when we want to call full class name in our module.config.php like the following :

use Application\Controller\IndexController;

return[
    'router' => [
        'routes' => [
            'home' => [
                'type' => 'Zend\Mvc\Router\Http\Literal',
                'options' => [
                    'route'    => '/',
                    'defaults' => [
                        'controller' => IndexController::class,
                        'action'     => 'index',
                    ],
                ],
            ],
        ],
    ],
    
    'controllers' => [
        'invokables' => [
            IndexController::class => IndexController::class
        ],
    ],
    
    // ...
];

b. finally keyword
Code within the finally block will always be executed after the try and catch blocks, regardless of whether an exception has been thrown, and before normal execution resumes.

try{
    $adapter->getDriver()->getConnection()->beginTransaction();
    
    $adapter->query("INSERT INTO album(artist, title) values('Ray', 'Love')")->execute();
    $lastInsertedId = $this->getAdapter()->getDriver()->getConnection()->getLastGeneratedValue(); 
    $adapter->query("INSERT INTO track(title, album_id) values('New Title', 'Foo')")->execute();
    
    $adapter->getDriver()->getConnection()->commit();
} catch(\Exception $e) {
    $adapter->getDriver()->getConnection()->rollback();
    throw $e;
} finally {
    $adapter->getDriver()->getConnection()->disconnect();        
}

3. PHP 5.6 features

Managing function parameters is now easier with Variadic and Argument Unpacking.
This is the old way :

class Bar {}
class Foo
{
    public function __construct(Bar $bar)
    {
        var_dump($bar);
        
        //getting argument list 
        $numargs = func_num_args();
        if ($numargs > 1) {
            $args = func_get_args();
            
            $options = array();
            foreach($args as $key => $row) {
                if ($key > 0 ) {
                    $options[] = $row;
                }
            }
            
            var_dump($options);
        }
    }
}

$foo = new Foo(new Bar, 'a', 'b', 'c', 'd');

This is the new way :

class Bar {}
class Foo
{
    public function __construct(Bar $bar, ...$options)
    {
        var_dump($bar);
        var_dump($options);
    }
}

$foo = new Foo(new Bar, 'a', 'b', 'c', 'd');

We can pack the argument list by : … too.

$options = [
    'a',
    'b',
    'c',
    'd'
];
$foo = new Foo(new Bar, ...$options);

// OR collect all of them in one array

$options = [
    new Bar,
    'a',
    'b',
    'c',
    'd'
];
$foo = new Foo(...$options);

This feature can be useful when managing service dependencies, for example :

namespace MyModule\Factory\Service;

use MyModule\Service\Bar;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;

class FooServiceFactory implements FactoryInterface
{
    public function createService(ServiceLocatorInterface $serviceLocator)
    {
        $options = [
            $serviceLocator->get('Bar'),
            'a',
            'b',
            'c',
            'd',
        ];
        
        $foo = new Foo(...$options);
        return $foo;
    }
}

Ok, I hope my post is useful. What PHP version you’re using ? :)

References :

1. http://php.net/manual/en/migration54.new-features.php
2. http://php.net/manual/en/migration55.new-features.php
3. http://php.net/manual/en/migration56.new-features.php
4. https://mwop.net/blog/2012-07-30-the-new-init.html
5. https://github.com/thomasbachem/php-short-array-syntax-converter

Zend Framework 2 : Translate ZF2 form label and value using translatorTextDomain

Posted in Tutorial PHP, Zend Framework 2 by samsonasik on September 22, 2014

zf2-zendframework2When you work with ZF2 Form, you can translate the form element label and element value by specify translatorTextDomain. It can be applied globally on Module class so all form will be applied with its translation.
For example, We have structure of our translation like this :
zf2-form-label-translation

We can create a translation file then

<?php

return array(
    'Address' => 'Alamat', // for label "Address"
    'Create'  => 'Buat',   // for Submit value "Create" 
);

Now, let’s configure the translator in the module.config.php

return array(
    // .. other array config here

    'translator' => array(
        'locale' => 'id',
        'translation_file_patterns' => array(
            array(
                'type' => 'phpArray',
                'base_dir' => 'vendor/zendframework/zendframework/resources/languages',
                'pattern' => '%s/Zend_Captcha.php',
                'text_domain' => 'formvalidation',
            ),
            array(
                'type' => 'phpArray',
                'base_dir' => 'vendor/zendframework/zendframework/resources/languages',
                'pattern' => '%s/Zend_Validate.php',
                'text_domain' => 'formvalidation',
            ),
            
            // for label and value that we define ourself ...
            array(
                'type'     => 'phpArray',
                'base_dir' => __DIR__ . '/../translation',
                'pattern' => '%s/site.php',
                'text_domain' => 'myformlabelandvalue',
            ), 
        ),
    ),
    
    // ...
);

Ok, so, we then can create a form for that demo :

namespace TranslationSample\Form;

use Zend\Form\Form;
use Zend\InputFilter\InputFilterProviderInterface;

class SampleForm extends Form implements InputFilterProviderInterface
{
    public function __construct()
    {
        parent::__construct('sampleform');
    }
    
    public function init()
    {
        $this->add(array(
            'name' => 'address',
            'type' => 'Textarea',
            'options' => array(
                'label' => 'Address',
            ),
        ));
        
        $this->add(array(
            'type' => 'Submit',
            'name' => 'create',
            'attributes' => array(
                'value'    => 'Create',
                'class'    => 'btn btn-success',
            ),
        ));
    }
    
    public function getInputFilterSpecification()
    {
        return array(
            array(
                'name' => 'address',
                'required' => true,
                'validators' => array(

                    array(
                        'name'    => 'StringLength',
                        'options' => array(
                            'min'      => 6,
                            'max'      => 200,
                        ),
                    ),
                    
                ),
            ),
        );
    }
}

The above setup need to be fired at Module::onBootstrap :

namespace TranslationSample;

use Zend\Mvc\MvcEvent;
use Zend\Validator\AbstractValidator;

class Module
{
    public function onBootstrap(MvcEvent $event)
    {
        $application    = $event->getApplication();
        $serviceManager = $application->getServiceManager();
        $translator     = $serviceManager->get('translator');
        // for validation
        AbstractValidator::setDefaultTranslator($translator, 'formvalidation'); 
        // for form element label and value
        $serviceManager->get('ViewHelperManager')
                       ->get('formcollection')
                       ->setTranslatorTextDomain('myformlabelandvalue');
    }

    // ...
}

So, when $this->formCollection($form); is called :

$form = $this->form;
$form->prepare();

echo $this->form()->openTag($form);
echo $this->formCollection($form);
echo $this->form()->closeTag();

then the label and value will use the translatortextdomain registered like this :

formcollection-zf2-translate

If you use formLabel or formRow individually, you can apply the translatorTextDomain into it.

I uploaded the full code at my github account : https://github.com/samsonasik/TranslationSample .

NOTE : based on feedback by Manuel Stosic, we can do this for specific resource in view like :

$this->formLabel()->setTranslatorTextDomain('myformlabelandvalue');
$this->formInput()->setTranslatorTextDomain('myformlabelandvalue');
$this->formButton()->setTranslatorTextDomain('myformlabelandvalue');

References :
1. https://gist.github.com/stefanotorresi/13da4d2c8e486927a2f8
2. https://github.com/zendframework/zf2/issues/5826

Zend Framework 2 : Using $creationOptions in PluginManager

Posted in Tutorial PHP, Zend Framework 2 by samsonasik on August 14, 2014

zf2-zendframework2$creationOptions is an optional parameter that we can pass on 2nd parameter when we get service from PluginManager. It can ease coding process when we need to pass a different parameter or injection on the fly while service is created. We can apply it in $invokableClasses or $factories.

Let’s take a look more deep with example. Let’s say, we have a module with PluginManager that collect service in there like this :
invokables-and-creationoptions

We need to call ‘bar’ service with injected Foo class. Ok, let’s start.
1. create PluginInterface

namespace ExamplePluginManagerCreationOptions\Service;

interface PluginInterface
{
    /*
     * @return void
     */  
    public function getProperty();
}

2. create a Foo class that implements PluginInterface

namespace ExamplePluginManagerCreationOptions\Service;

class Foo implements PluginInterface
{
    /**
     * @var string
     */
    protected $fooProperty;
    
    /**
     * Construct with $fooProperty param
     * @param array $fooProperty
     */
    public function __construct(array $fooProperty)
    {
        $this->fooProperty = $fooProperty;    
    }
    
    /**
     * {@inheritdoc}
     */
    public function getProperty()
    {
        var_dump($this);
    }
}

3. create a Bar class that implements PluginInterface and use Foo in __construct.

namespace ExamplePluginManagerCreationOptions\Service;

class Bar implements PluginInterface
{
    /**
     * @var Foo
     */
    protected $foo;
    
    /**
     * Construct with $foo param
     * @param Foo $foo
     */
    public function __construct(Foo $foo)
    {
        $this->foo = $foo;    
    }
    
    /**
     * {@inheritdoc}
     */
    public function getProperty()
    {
        var_dump($this);
    }
}

4. When realizing the dependency above. We usually use factory to create service, but with $creationOptions, we can make it as invokables like the following :

namespace ExamplePluginManagerCreationOptions\Service;
 
use Zend\ServiceManager\AbstractPluginManager;
 
class PluginManager extends AbstractPluginManager
{
    protected $invokableClasses = array(
        'bar' => 'ExamplePluginManagerCreationOptions\Service\Bar',
    );
 
    /**
     * {@inheritdoc}
     */
    public function validatePlugin($plugin)
    {
        if ($plugin instanceof PluginInterface) {
            // we're okay
            return;
        }
 
        throw new \InvalidArgumentException(sprintf(
            'Plugin of type %s is invalid; must implement %s\PluginInterface',
            (is_object($plugin) ? get_class($plugin) : gettype($plugin)),
            __NAMESPACE__
        ));
    }
}

5. Then, we register the pluginmanager at PluginManagerFactory as PLUGIN_MANAGER_CLASS const as usual.

namespace ExamplePluginManagerCreationOptions\Factory;
 
use Zend\Mvc\Service\AbstractPluginManagerFactory;
 
class PluginManagerFactory extends AbstractPluginManagerFactory
{
    const PLUGIN_MANAGER_CLASS = 'ExamplePluginManagerCreationOptions\Service\PluginManager';
}

6. Now, we can register at service_manager key in module.config.php

return array(
    'service_manager' => array(
        'factories' => array(
            'testpluginmanager' => 'ExamplePluginManagerCreationOptions\Factory\PluginManagerFactory',  
        ),
    ),
);

7. Ok, then now we can call it :

$testpluginmanager = $this->getServiceLocator()->get('testpluginmanager');
        
$bar = $testpluginmanager->get(
    'bar',
    new \ExamplePluginManagerCreationOptions\Service\Foo(array('test'))
);
$bar->getProperty();

Hm.., do you feel pass everything of instance(s) on the fly when creating service is too much but still want “on the fly” freedom ? Then we can create a factory for it. We can then add “BarServiceFactory” like the following structure :
factories-and-creationoptions
The “BarServiceFactory” can be like the following :

namespace ExamplePluginManagerCreationOptions\Factory\Service;

use ExamplePluginManagerCreationOptions\Service\Bar;
use ExamplePluginManagerCreationOptions\Service\Foo;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\MutableCreationOptionsInterface;
use Zend\ServiceManager\ServiceLocatorInterface;

/**
 * a factory to create ExamplePluginManagerCreationOptions\Service\Bar
 * service
 */
class BarServiceFactory implements
    FactoryInterface,
    MutableCreationOptionsInterface
{
    /**
     * {@inheritdoc}
     */
    public function setCreationOptions(array $creationOptions)
    {
        $this->creationOptions = $creationOptions;
    }
    
    /**
     * {@inheritdoc}
     */
    public function createService(ServiceLocatorInterface $serviceLocator)
    {
        //you can call other service by $serviceLocator()->get('servicename')
        //as far as the service implements PluginInterface defined in
        //your pluginmanager
        //otherwise, you need to call top serviceManager
        //by $serviceLocator->getServiceLocator()->get('servicename')
        return new Bar(new Foo($this->creationOptions));
    }
}

Now, we can register it at out PluginManager.

namespace ExamplePluginManagerCreationOptions\Service;
 
use Zend\ServiceManager\AbstractPluginManager;
 
class PluginManager extends AbstractPluginManager
{
    protected $invokableClasses = array(
        'bar' => 'ExamplePluginManagerCreationOptions\Service\Bar',
    );
    
    protected $factories = array(
        'barservice' => 'ExamplePluginManagerCreationOptions\Factory\Service\BarServiceFactory',
    );
    
    /**
     * {@inheritdoc}
     */
    public function validatePlugin($plugin)
    {
        if ($plugin instanceof PluginInterface) {
            // we're okay
            return;
        }
 
        throw new \InvalidArgumentException(sprintf(
            'Plugin of type %s is invalid; must implement %s\PluginInterface',
            (is_object($plugin) ? get_class($plugin) : gettype($plugin)),
            __NAMESPACE__
        ));
    }
}

And now, we can call it with :

$testpluginmanager = $this->getServiceLocator()->get('testpluginmanager');
        
$bar = $testpluginmanager->get(
    'barservice', 
    array('test')
);
$bar->getProperty();

When everything is ok, then we can get the following data output :

object(ExamplePluginManagerCreationOptions\Service\Bar)[303]
  protected 'foo' => 
    object(ExamplePluginManagerCreationOptions\Service\Foo)[298]
      protected 'fooProperty' => 
        array (size=1)
          0 => string 'test' (length=4)

Done ;). I hope it is useful.

Note : We can make $this->creationOptions as collection of array of instances too.

References :
1. http://zend-framework-community.634137.n4.nabble.com/Abstract-Factory-for-custom-Validators-options-discarded-td4661990.html
2. http://zend-framework-community.634137.n4.nabble.com/AbstractPluginManager-amp-options-creationOptions-will-not-work-as-newInstanceArgs-td4656077.html#a4656083

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 .

Zend Framework 2 : Using DoctrineModule\Form\Element\ObjectSelect and custom repository

Posted in Tutorial PHP, Zend Framework 2 by samsonasik on May 22, 2014

zf2-zendframework2When we are using Doctrine2 in Zend Framework 2 project, we can use existing module named DoctrineModule that can be used to easist our job. Now I will explain about how to use DoctrineModule\Form\Element\ObjectSelect in our Form to load data into select element with custom query instead of default one.
For example, we have data like this :
countries-continent
Now, we need to build a form element that collect continent data, that’s means, we need to ‘group by continent’ for query-ing the table data like this :
continent-grab
To make it work, we need to create custom repository. Ok, let’s start.
1. Prepare the Entity

//module/Tutorial/src/Tutorial/Entity/Countries.php
namespace Tutorial\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Countries
 *
 * @ORM\Table(name="countries")
 * @ORM\Entity(repositoryClass="Tutorial\Repository\CountriesRepository")
 */
class Countries
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="bigint", nullable=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="country", type="string", length=30, nullable=false)
     */
    private $country;

    /**
     * @var string
     *
     * @ORM\Column(name="continent", type="string", length=30, nullable=false)
     */
    private $continent;



    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set country
     *
     * @param string $country
     * @return Countries
     */
    public function setCountry($country)
    {
        $this->country = $country;

        return $this;
    }

    /**
     * Get country
     *
     * @return string 
     */
    public function getCountry()
    {
        return $this->country;
    }

    /**
     * Set continent
     *
     * @param string $continent
     * @return Countries
     */
    public function setContinent($continent)
    {
        $this->continent = $continent;

        return $this;
    }

    /**
     * Get continent
     *
     * @return string 
     */
    public function getContinent()
    {
        return $this->continent;
    }
}

Above entity is pretty generic, but we add new “repositoryClass” attribute in the @ORM\Entity annotation to linked with our custom repository.
2. Create a custom repository

//module/Tutorial/src/Tutorial/Repository/CountriesRepository.php
namespace Tutorial\Repository;

use Doctrine\ORM\EntityRepository;

class CountriesRepository extends EntityRepository
{
    public function getContinent()
    {
        $querybuilder = $this->_em
                             ->getRepository($this->getEntityName())
                             ->createQueryBuilder('c');
        return $querybuilder->select('c')
                    ->groupBy('c.continent')
                    ->orderBy('c.id', 'ASC')
                    ->getQuery()->getResult();
    }
}

The getContinent grab the countries data group by continent.
3. Create form

//module/Tutorial/src/Tutorial/Form/CountriesForm.php
namespace Tutorial\Form;

use Zend\Form\Form;
use Zend\InputFilter\InputFilterProviderInterface;
use Doctrine\ORM\EntityManager;

class CountriesForm extends Form
    implements InputFilterProviderInterface
{
    protected $entityManager;
    
    public function __construct(EntityManager $entityManager)
    {
        parent::__construct();

        $this->entityManager = $entityManager;       
    }
    
    public function init()
    {
        $this->add(array(
           'name' => 'continent',
           'type' => 'DoctrineModule\Form\Element\ObjectSelect',
           'options' => array(
                'object_manager'     => $this->entityManager,
                'target_class'       => 'Tutorial\Entity\Countries',
                'property' => 'continent',
                'is_method' => true,
                'find_method'        => array(
                    'name'   => 'getContinent',
                ),
            ), 
        ));
    }
    
    public function getInputFilterSpecification()
    {
        return array(); // filter and validation here
    }
}

We need to inject form with Doctrine\ORM\EntityManager, and call the getContinent method that we already define at our CountriesRepository. So the Form need to be created via factory :

//module/Tutorial/src/Tutorial/Factory/Form/CountriesFormFactory.php
namespace Tutorial\Factory\Form;

use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Tutorial\Form\CountriesForm;

class CountriesFormFactory implements FactoryInterface
{
    public function createService(ServiceLocatorInterface $serviceLocator)
    {
        $services         = $serviceLocator->getServiceLocator();
        $entityManager    = $services->get('Doctrine\ORM\EntityManager');
        
        $form = new CountriesForm($entityManager);
        return $form;
    }
}

4. Create controller

//module/Tutorial/src/Tutorial/Controller/CountriesController.php
namespace Tutorial\Controller;

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

class CountriesController extends AbstractActionController
{
    protected $countriesForm;
    
    public function __construct(FormInterface $countriesForm)
    {
        $this->countriesForm = $countriesForm;
    }
    
    public function indexAction()
    {
        return new ViewModel(array(
            'form' => $this->countriesForm, 
        ));
    }
}

We need to inject controller with the CountriesForm, so the Controller need to be created via factory :

//module/Tutorial/src/Tutorial/Factory/Controller/CountriesControllerFactory.php
namespace Tutorial\Factory\Controller;

use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Tutorial\Controller\CountriesController;

class CountriesControllerFactory implements FactoryInterface
{
    public function createService(ServiceLocatorInterface $serviceLocator)
    {
        $services       = $serviceLocator->getServiceLocator();
        $countryForm    = $services->get('FormElementManager')->get('Tutorial\Form\CountriesForm');
        $controller = new CountriesController($countryForm);

        return $controller;
    }
}

5. Register services

//module/Tutorial/config/module.config.php
return array(
    'doctrine' => array(
        'driver' => array(
            'Tutorial_Entities' => array(
                'class' =>'Doctrine\ORM\Mapping\Driver\AnnotationDriver',
                'cache' => 'array',
                'paths' => array(__DIR__ . '/../src/Tutorial/Entity')
            ),
            'orm_default' => array(
                'drivers' => array(
                    'Tutorial\Entity' => 'Tutorial_Entities'
                ),
            ),
        ),
    ),
    
    'controllers' => array(
        'factories' => array(
            'Tutorial\Controller\Countries' => 'Tutorial\Factory\Controller\CountriesControllerFactory',  
        ),
    ),
    
    'form_elements' => array(
        'factories' => array(
            'Tutorial\Form\CountriesForm' => 'Tutorial\Factory\Form\CountriesFormFactory',  
        ),
    ),
    
    'router' => array(
        'routes' => array(
            'countries' => array(
                'type'    => 'segment',
                'options' => array(
                    'route'    => '/countries[/:action]',
                    'constraints' => array(
                        'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
                    ),
                    'defaults' => array(
                        'controller' => 'Tutorial\Controller\Countries',
                        'action'     => 'index',
                    ),
                ),
            ),
        ),
    ),
    
    'view_manager' => array(
        'template_path_stack' => array(
            'tutorial' => __DIR__ . '/../view',
        ),
    ),
    
);

6. Last but not least, build a view :

// module/Tutorial/view/tutorial/countries/index.phtml
$form = $this->form;
$form->prepare();

echo $this->form()->openTag($form);
echo $this->formCollection($form);
echo $this->form()->closeTag();

Ok, done ;)

Zend Framework 2 : Getting real Sql String of Zend\Db

Posted in Tutorial PHP, Zend Framework 2 by samsonasik on May 16, 2014

zf2-zendframework2 I know, this is maybe a simple post for you, but it useful for me :). Hope it useful for someone. When we build a query using Zend\Db, sometime, complex query need checking for debugging to make sure our query is right. For example, we need to make sure we build a query like this :

SELECT `album`.* FROM `album` WHERE `title` = 'abracadabra' AND (`id` = '1' OR `artist` = 'Tony') LIMIT 1

And we already have an \Zend\Db\Sql\Select instance. In case if you have Model class like zf2 docs provide

$sql = $this->tableGateway->getSql();
$select = $sql->select();
$select->where(array('title' => 'abracadabra'));
$select->where
  ->NEST->
        equalTo('id', 1)
            ->OR->
        equalTo('artist', 'Tony')
  ->UNNEST;

$select->limit(1);

So, Before we return it with :

return $this->tableGateway->selectWith($select);

We can check it with :

echo $sql->getSqlstringForSqlObject($select); die ; // ( die/exit to debugging purpose )
//it will print sql string :
// SELECT `album`.* FROM `album` WHERE `title` = 'abracadabra' AND (`id` = '1' OR `artist` = 'Tony') LIMIT 1

That will return the real sql build for our specific platform.

references :
https://github.com/zendframework/zf2/issues/3224

Don’t push yourself

Posted in Psychology by samsonasik on May 8, 2014

When I was a child, I wished I will be an army. And.. it is not granted. In sport, I’m not good at all. So, it will not be good if I push myself to make it happen. Albert Einstein said, “Everybody is a genius. But if you judge a fish by it’s ability to climb a tree, it will live its whole life believing that it is stupid.”. This realized me that I should do what I can and better at that part. From highschool, I like to write poems. That’s my ability. I’m not saying that I’m good on writing poems, but I can say that it’s better for me to write a poem rather than push myself to do sport that I can’t handle. Now, I’m a web developer, it is better to me to code rather than to do networking job.
It doesn’t means that you should surrender at your condition, but you should understand that you have things that if you do it well, it will be great for you. So, know your weakness, know your strong suit. Do what your best ability.

reference :
image : https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcQkwkta-0K4qeu9QkMNw6J1p_sHaIiq7lHiLMfpTHlLxFE9nZ5B
quote : http://www.goodreads.com/quotes/101458-everybody-is-a-genius-but-if-you-judge-a-fish

Zend Framework 2 : Using INSERT INTO … SELECT with Zend\Db

Posted in Tutorial PHP, Zend Framework 2 by samsonasik on March 19, 2014

zf2-zendframework2Zend Framework 2.3.0 released with dozen of features. One of feature on Zend\Db is we can make insert using select instance. It can make life easier when you have a situation, for example : to ‘copy’ the content of some table to other table, for example : migration with some criteria need to be achieved. Here we go :

//this example is when we use component instead of full stack framework
include './vendor/autoload.php';

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

$adapterSelect = new Zend\Db\Adapter\Adapter(array(
    'driver'   => 'pdo_mysql',
    'database' => 'DbSELECT',
    'username' => 'root',
    'password' => ''
));

$adapterInsert = new Zend\Db\Adapter\Adapter(array(
    'driver'   => 'pdo_mysql',
    'database' => 'DbINTO',
    'username' => 'root',
    'password' => ''
));

/**
 * php 5.4 code, for php 5.3 code, you can extract with
   $selectedtable = new Zend\Db\TableGateway\TableGateway('tableneedtobeselected', $adapterSelect);
   $select = $selectedtable->getSql()->select()->where(array('field' => 'value'));
 */
$select = (new Zend\Db\TableGateway\TableGateway('tableneedtobeselected', $adapterSelect))
                ->getSql()->select()
                ->where(array('field' => 'value'));

/**
 * table that need to be inserted
 */
$tableToBeInserted = new Zend\Db\TableGateway\TableGateway('tablenamewillinserted', $adapterInsert);

//insert with select
$tableToBeInserted->insert($select);

Done ;)

References :
1. http://framework.zend.com/blog/zend-framework-2-3-0-released.html

Zend Framework 2 : Utilize ValidatorManager to work with Custom Validator in Zend\Form

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

zf2-zendframework2ValidatorManager is a Plugin Manager that corresponding to Zend\Validator\ValidatorPluginManager, and used to manage validator instances. While we work with existing validators in Zend\Form, we can call validators in ‘validators’ key under inputFilter specification with the ‘invokables’ registered service at Zend\Validator\ValidatorPluginManager. In this post, I will propose detail way to work with custom validator.

For example, we have custom validator named Special to handle words with at least one special character in it, so the form when not valid will show like this :
form-validator-custom
So, we need to start with creating the validator like the following :

//filename : module/TutorialValidator/src/TutorialValidator/Validator/Special.php
namespace TutorialValidator\Validator;

use Zend\Validator\AbstractValidator;
                    
class Special extends AbstractValidator
{
    const NOTSPECIAL = 'NOTSPECIAL';

    protected $messageTemplates = array(
        self::NOTSPECIAL => 'Value should at least one special character',
    );
    
    public function __construct(array $options = array())
    {
       parent::__construct($options);
    }

    public function isValid($value)
    {
       $this->setValue($value);
       
       $special   = preg_match('#[\W]{1,}#', $value);

       if (!$special) {
           $this->error(self::NOTSPECIAL);
           return false;
       }

       return true;
    }
}

And we need to use it to validate the forms, so we need to register the validator in ‘validators’ key in our configuration:

//filename : module/TutorialValidator/config/module.config.php
'validators' => array(
    'invokables' => array(
        'Special' => 'TutorialValidator\Validator\Special'  
     ),
),

There are two ways to build form with custom validator.

A. We can use Zend\Form\FormAbstractServiceFactory that can be configured via ‘forms’ key in configuration files.
To do this, we need to :
1. register Zend\Form\FormAbstractServiceFactory into configuration

//filename : module/TutorialValidator/config/module.config.php
'service_manager' => array(
    //other service registration here...
    'abstract_factories' => array(
        'Zend\Form\FormAbstractServiceFactory',
    ),
    //other service registration here...
),

2. And then, configure the ‘forms’

//filename : module/TutorialValidator/config/module.config.php
'forms' => array(
    'SampleForm' => array(
        'hydrator' => 'ObjectProperty',
        'type'     => 'Zend\Form\Form',
        'elements' => array(
            array(
                'spec' => array(
                    'type' => 'Text',
                    'name' => 'sampleinput',
                    'options' => array(
                        'label' => 'Sample Input:',
                    )
                ),
            ),
            array(
                'spec' => array(
                    'type' => 'Submit',
                    'name' => 'submit',
                    'attributes' => array(
                        'value' => 'Go',
                    )
                ),
            ),
        ),
        'input_filter' => array(
            'sampleinput' => array(
                'required'   => true,
                'validators' => array(
                    array(
                        'name' => 'Special',
                    ),
                ),
            ),
        ),
    ),
),

SampleForm is a registered form service that can be called via ‘FormElementManager’ manager. Special is a custom validator that registered at ‘validators’ key or getValidatorConfig() under Module class.

B. Using form class
For form class, we need to implements Zend\InputFilter\InputFilterProviderInterface and implement method getInputFilterSpecification :
To do this, we need to :
1. create the form class

//filename : module/TutorialValidator/src/TutorialValidator/Form/SampleForm.php
namespace TutorialValidator\Form;

use Zend\Form\Form;
use Zend\InputFilter\InputFilterProviderInterface;

class SampleForm extends Form implements InputFilterProviderInterface
{
    public function init()
    {
        $this->add(array(
            'name' => 'sampleinput',
            'type' => 'Text',
            'options' => array(
                'label' => 'Sample Input: ',
            ),
        ));

        $this->add(array(
            'name' => 'submit',
            'attributes' => array(
                'type'  => 'submit',
                'value' => 'Go',
                'id' => 'submitbutton',
            ),
        ));
    }

    public function getInputFilterSpecification()
    {
        return array(
            array(
                'name' => 'sampleinput',
                'required' => true,
                'validators' => array(
                    array('name' => 'Special'),
                ),
            ),
        );
    }
}

2. Register form service in ‘form_elements’ key in config

//filename : module/TutorialValidator/config/module.config.php
'form_elements' => array(
    'invokables' => array(
        'SampleForm' => 'TutorialValidator\Form\SampleForm'
    ),                         
),

When everything is OK, we can call the form via ‘FormElementManager’ in controller ( you can inject controller with SampleForm service via ‘factories’ key of course :)) :

    public function indexAction()
    {
        $form = $this->getServiceLocator()
                     ->get('FormElementManager')
                     ->get('SampleForm');
        
        $request = $this->getRequest();
        if ($request->isPost()) {
            $form->setData($request->getPost());
            if ($form->isValid()) {
                echo 'Great!form is valid';
            }
        }
        
        $viewmodel = new ViewModel;
        $viewmodel->setVariable('form', $form);
        
        return $viewmodel;
    }

Done. I’ve uploaded the sample code to my github account : https://github.com/samsonasik/TutorialValidator . Hope it helpful ;)

Note : Thanks to Daniel Gimenes for the suggestion to this post and make a PR to my repository on github.
danizord-suggestion-on-getInputFilterSpecification

References :
1. http://zf2.readthedocs.org/en/latest/modules/zend.mvc.services.html
2. http://stackoverflow.com/questions/19642139/possible-to-create-a-factory-to-instantiate-custom-form-validators
3. http://stackoverflow.com/questions/13476164/zend-framework-2-custom-validators-for-forms
4. https://github.com/samsonasik/TutorialValidator/pull/1

Zend Framework 2 : Getting Closer with PluginManager

Posted in Tutorial PHP, Zend Framework 2 by samsonasik on January 29, 2014

zf2-zendframework2In ZF2, there is PluginManager that we can use to collect services with same contract interfaces or ancestor class into single class properties. After that, we can validate whenever the plugins as services are instance of that interfaces or ancestor class ( usually an abstract class ). There are properties of PluginManager class that can collect the services :
1. $factories
2. $invokableClasses
3. $aliases(aliasing registered services at $factories or $invokableClasses)
The basic class structure of PluginManager is like this :

namespace YourModule;

use Zend\ServiceManager\AbstractPluginManager;

class PluginManager extends AbstractPluginManager
{
    protected $factories = array(
        //represent factories key
    );
    
    protected $invokableClasses = array(
        //represent invokables key
    );
    
    protected $aliases = array(
        //represent aliases key
    );
    
    public function validatePlugin($plugin)
    {
        if ($plugin instanceof Plugin\PluginInterface) {
            // we're okay
            return;
        }
        
        throw new \InvalidArgumentException(sprintf(
            'Plugin of type %s is invalid; must implement %s\Plugin\PluginInterface',
            (is_object($plugin) ? get_class($plugin) : gettype($plugin)),
            __NAMESPACE__
        ));
    }
}

For example, you need to create collection of services that can convert content into another format, for example, you want to create services that can convert to ‘xls’, ‘pdf’, or other. so you can create pluginmanager to collect that services, like the following :
pluginmanager_shot
Let’s code!
1. create the ConverterContentPluginManager PluginManager

//filename : module/Tutorial/src/Tutorial/ConverterContentPluginManager.php
namespace Tutorial;

use Zend\ServiceManager\AbstractPluginManager;

class ConverterContentPluginManager extends AbstractPluginManager
{
    protected $invokableClasses = array(
        //represent invokables key
        'xls' => 'Tutorial\Plugin\Xls',
        'pdf' => 'Tutorial\Plugin\Pdf'
    );

    public function validatePlugin($plugin)
    {
        if ($plugin instanceof Plugin\PluginInterface) {
            // we're okay
            return;
        }

        throw new \InvalidArgumentException(sprintf(
            'Plugin of type %s is invalid; must implement %s\Plugin\PluginInterface',
            (is_object($plugin) ? get_class($plugin) : gettype($plugin)),
            __NAMESPACE__
        ));
    }
}

2. Create the plugin interface to be implemented

//filename : module/Tutorial/src/Tutorial/Plugin/PluginInterface.php
namespace Tutorial\Plugin;

interface PluginInterface
{
    public function convert($content);
}

3. Create that services
a. the Xls service

//filename : module/Tutorial/src/Tutorial/Plugin/Xls.php
namespace Tutorial\Plugin;

class Xls implements PluginInterface
{   
    public function convert($content)
    {
        echo 'xls convert here';
        //implementation of convert $content to convert content into xls
    }
}

b. the Pdf service

//filename : module/Tutorial/src/Tutorial/Plugin/Pdf.php
namespace Tutorial\Plugin;

class Pdf implements PluginInterface
{   
    public function convert($content)
    {
        echo 'pdf convert here';
        //implementation of convert $content to convert content into pdf
    }
}

4. Create a factory class for the ConverterContentPluginManager

//filename : module/Tutorial/src/Tutorial/Service/ConverterContentPluginManagerFactory.php
namespace Tutorial\Service;

use Zend\Mvc\Service\AbstractPluginManagerFactory;

class ConverterContentPluginManagerFactory extends AbstractPluginManagerFactory
{
    const PLUGIN_MANAGER_CLASS = 'Tutorial\ConverterContentPluginManager';
}

5. Last step, register into service manager ( just one service, the ConverterContentPluginManagerFactory one )

//filename : module/Tutorial/config/module.config.php
return array(
    'service_manager' => array(
        'factories' => array(
            'convertercontent' => 'Tutorial\Service\ConverterContentPluginManagerFactory'  
        ),
    ),
);

Ok, now you can grab the plugins via :

$content = 'sample content you want to convert';
$converter = $this->getServiceLocator()->get('convertercontent')
$converter->get('xls')->convert($content);
$converter->get('pdf')->convert($content);

Done ;)

References :
1. http://raing3.gshi.org/2013/05/26/creating-custom-plugin-manager-in-zend-framework-2/
2. http://zf2.readthedocs.org/en/latest/modules/zend.mvc.services.html

Zend Framework 2 : Handle and Catch E_* PHP errors

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

zf2-zendframework2I made this post because real application is hard ( err…, not as easy as we imagine ) . One error exposed to user can be harmful for our site. As developer, there is a time that something can go wrong even it unit tested ( because we are human!). The ‘dispatch.error’ and ‘render.error’ are errors that handled by Framework to handle “framework specific” error, like  service not found, or view file not found. But what if the error is PHP Error Constant, like you forgot to handle empty array and just :

$array = array();
//many complex things here
//and you echoing..
 echo $array[1];
//that is empty...

You will got error like this : Notice: Undefined offset: 1 in /your/path/to/file.
It’s very dangerous because it exposed to your user. We need to fix it as soon as possible!, so when we need on site access, we need to automate logging ( for example, save error to file and send mail) with the error described and show user that something is go wrong and developer is working to fix it.

Ok, first, prepare the view file that will show user that something is go wrong :

<!-- //module/Application/view/error/e_handler.phtml -->
website is down right now :), we are working on it. please come back again...

Next, we create code to handle the PHP E_* errors :

// ./e_errorhandler.php in root of ZF2 app
//adapt from http://stackoverflow.com/questions/277224/how-do-i-catch-a-php-fatal-error
define('E_FATAL',  E_ERROR | E_USER_ERROR | E_PARSE | E_CORE_ERROR |
        E_COMPILE_ERROR | E_RECOVERABLE_ERROR);

define('DISPLAY_ERRORS', TRUE);
define('ERROR_REPORTING', E_ALL | E_STRICT);

register_shutdown_function('shut');
set_error_handler('handler');

//catch function
function shut()
{
    $error = error_get_last();
    if ($error && ($error['type'] & E_FATAL)) {
        handler($error['type'], $error['message'], $error['file'], $error['line']);
    }
}

function handler($errno, $errstr, $errfile, $errline)
{
    switch ($errno) {

        case E_ERROR: // 1 //
            $typestr = 'E_ERROR'; break;
        case E_WARNING: // 2 //
            $typestr = 'E_WARNING'; break;
        case E_PARSE: // 4 //
            $typestr = 'E_PARSE'; break;
        case E_NOTICE: // 8 //
            $typestr = 'E_NOTICE'; break;
        case E_CORE_ERROR: // 16 //
            $typestr = 'E_CORE_ERROR'; break;
        case E_CORE_WARNING: // 32 //
            $typestr = 'E_CORE_WARNING'; break;
        case E_COMPILE_ERROR: // 64 //
            $typestr = 'E_COMPILE_ERROR'; break;
        case E_CORE_WARNING: // 128 //
            $typestr = 'E_COMPILE_WARNING'; break;
        case E_USER_ERROR: // 256 //
            $typestr = 'E_USER_ERROR'; break;
        case E_USER_WARNING: // 512 //
            $typestr = 'E_USER_WARNING'; break;
        case E_USER_NOTICE: // 1024 //
            $typestr = 'E_USER_NOTICE'; break;
        case E_STRICT: // 2048 //
            $typestr = 'E_STRICT'; break;
        case E_RECOVERABLE_ERROR: // 4096 //
            $typestr = 'E_RECOVERABLE_ERROR'; break;
        case E_DEPRECATED: // 8192 //
            $typestr = 'E_DEPRECATED'; break;
        case E_USER_DEPRECATED: // 16384 //
            $typestr = 'E_USER_DEPRECATED'; break;
    }
    
    $message = " Error PHP in file : ".$errfile." at line : ".$errline."
    with type error : ".$typestr." : ".$errstr." in ".$_SERVER['REQUEST_URI'];

    if(!($errno & ERROR_REPORTING)) {
        return;
    }

    if (DISPLAY_ERRORS) {
        //logging...
        $logger = new Zend\Log\Logger;
		
        //stream writer			
        $writerStream = new Zend\Log\Writer\Stream(__DIR__.'/data/logs/'.date('Ymd').'-log.txt');
        //mail writer
        $mail = new Zend\Mail\Message();
        $mail->setFrom('system@yoursite.com', 'Sender\'s name');
        $mail->addTo('team@yoursite.com', 'Your Site Team');
        $transport = new Zend\Mail\Transport\Sendmail(); 
        $writerMail = new Zend\Log\Writer\mail($mail, $transport);
        $writerMail->setSubjectPrependText("PHP Error :  $typestr : $errstr ");
        
        $logger->addWriter($writerStream);
        $logger->addWriter($writerMail);
      
        //log it!
        $logger->crit($message);
        
        //show user that's the site is down right now
        include __DIR__.'/module/Application/view/error/e_handler.phtml';
        die;
    }
}

The code line 61-87 is show how to log it and show user custom error page immediately.
Ok, time to include the handler in public/index.php and keep silent ( @ for parse error ) for showing error :

/**
 * This makes our life easier when dealing with paths. Everything is relative
 * to the application root now.
 */
chdir(dirname(__DIR__));

// Decline static file requests back to the PHP built-in webserver
if (php_sapi_name() === 'cli-server' && is_file(__DIR__ . parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH))) {
    return false;
}

// Setup autoloading
require 'init_autoloader.php';
//Setup error handler
require_once 'e_errorhandler.php';

// Run the application!
@Zend\Mvc\Application::init(require 'config/application.config.php')->run();

Ok, done! Hope helpful ;)

References :
1. http://stackoverflow.com/questions/277224/how-do-i-catch-a-php-fatal-error
2. http://zf2.readthedocs.org/en/latest/modules/zend.mail.introduction.html
3. http://zf2.readthedocs.org/en/latest/modules/zend.log.writers.html

Zend Framework 2 : using PSR-4 autoloader in your Module

Posted in Tutorial PHP, Zend Framework 2 by samsonasik on January 11, 2014

zf2-zendframework2 This post is inspired by Phil Sturgeon blog post about Autoloading Laravel application code with PSR-4. It can be applied when you’re using Zend Framework module. Instead of using default structure, you can define the structure like this.zf2-module-with-psr-4The Classes inside Controller folder will have namespace Foo\Controller, and in the Model folder will have namespace Foo\Model.
Ok, let’s make it happen!
1. Let’s the Module::getAutoloaderConfig() function empty

//module/Foo/Module.php
namespace Foo;

class Module
{
    public function getConfig()
    {
        return include __DIR__ . '/config/module.config.php';
    }

    public function getAutoloaderConfig()
    {
    }
}

2. Configure composer.json
Add psr-4 autolaod config into your composer.json.

{
    "autoload": {
        "psr-4":{
            "Foo\\" : "module/Foo/src/"
        }
    },
    "require": {
        "php": ">=5.3.3",
        "zendframework/zendframework": "2.2.5"
    }
}

3. update composer

$ php composer.phar self-update
Updating to version 69e77fbbb564e57a6c1a97eaa3c8b751bab70688.
    Downloading: 100% 

4. Run dump-autoload

$ php composer.phar dump-autoload
Generating autoload files

5. Now, You are getting new generated autoload file named vendor/composer/autoload_psr4.php automatically

// autoload_psr4.php @generated by Composer

$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);

return array(
    'Foo\\' => array($baseDir . '/module/Foo/src'),
);

6. Perfect!, Let’s creating file for samples
a. the model class

//module/Foo/src/Model/FooModel.php
namespace Foo\Model;

class FooModel
{
    function __construct()
    {
        echo "foo";
    }
}

b. the controller class

//module/Foo/src/Controller/FooController.php
namespace Foo\Controller;

use Zend\Mvc\Controller\AbstractActionController;

class FooController extends AbstractActionController
{
    public function indexAction()
    {
        new \Foo\Model\FooModel();
        die; //break for test
    }
}

c. the config/module.config.php

//module/Foo/config/module.config.php
return array(
    'router' => array(
        'routes' => array(
            'foo' => array(
                'type' => 'Zend\Mvc\Router\Http\Literal',
                'options' => array(
                    'route'    => '/foo',
                    'defaults' => array(
                        'controller' => 'Foo\Controller\Foo',
                        'action'     => 'index',
                    ),
                ),
            ),
        ),
    ),
    'controllers' => array(
        'invokables' => array(
            'Foo\Controller\Foo' => 'Foo\Controller\FooController'
        ),
    ),
);

7. Register your module into config/application.config.php as usual.

return array(
    'modules' => array(
        'Application',
        'Foo'
    ),
    'module_listener_options' => array(
        'module_paths' => array(
            './module',
            './vendor',
        ),
        'config_glob_paths' => array(
            'config/autoload/{,*.}{global,local}.php',
        ),
    ),
);

8. Let’s call in browser : http://yourapphost/foo , if it’s working as planned, it will show us :
foo-screen-call

Done! I hope this post helpful.

References :
1. http://philsturgeon.co.uk/blog/2014/01/autoloading-laravel-application-code-with-psr4
2. https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md
3. http://akrabat.com/zend-framework-2/thoughts-on-module-directory-structure/
4. http://zf2.readthedocs.org/en/latest/user-guide/modules.html

Follow

Get every new post delivered to your Inbox.

Join 261 other followers