Welcome to Abdul Malik Ikhsan's Blog

Testing Hard Dependency with AspectMock

Posted in Teknologi, Tutorial PHP by samsonasik on January 28, 2016

This is another testing legacy application post. Don’t tell your client/other people to refactor, if your job is only to make tests for it, as at some situations, there are reasons to not refactor. You may have situation to test hard dependency that impossible to be mocked and stubbed. There is a library named AspectMock for it, that you can use in PHPUnit, for example.

So, to have it, you can require via composer:

composer require "codeception/aspect-mock:^0.5.5" --dev

For example, you have the following class:

namespace App;

class MyController
{
    public function save()
    {
        $user = new User();
        if (! $user->save()) {
            echo 'not saved';
            return;
        }

        echo 'saved';
    }
}

That bad, huh! Ok, let’s deal to tests it even you don’t really like it. First, setup your phpunit.xml to have ‘backupGlobals=”false”‘ config:

<?xml version="1.0" encoding="UTF-8"?>

<phpunit
    colors="true"
    backupGlobals="false"
    bootstrap="bootstrap.php">
    <testsuites>
        <testsuite name="AppTest">
            <directory suffix=".php">./test</directory>
        </testsuite>
    </testsuites>
    <filter>
        <whitelist addUncoveredFilesFromWhitelist="true">
            <directory suffix=".php">./src</directory>
        </whitelist>
    </filter>
</phpunit>

Now, based on config above, you can create bootstrap.php:

include 'vendor/autoload.php';

use AspectMock\Kernel;

$kernel = Kernel::getInstance();
$kernel->init([
    'debug' => true,
    'cacheDir' => __DIR__ . '/data/cache',
    'includePaths' => [__DIR__.'/src'],
]);

Assumption: You have ‘./data/cache’ for saving cache and ‘src/’ for your source code directory, if you use your own autoloader, you can add:

// ...
$kernel->loadFile('YourAutoloader.php');

as the AspectMock documentation mentioned.

Now, time to write the tests:

  1. Preparation
    namespace AppTest;
    
    use PHPUnit_Framework_TestCase;
    use App\MyController;
    use AspectMock\Test as test;
    
    class MyControllerTest extends PHPUnit_Framework_TestCase
    {
        private $myController;
    
        protected function setUp()
        {
            $this->myController = new MyController;
        }
    
        protected function tearDown()
        {
            test::clean(); // remove all registered test doubles
        }
    }
    

  2. write the test cases

class MyControllerTest extends PHPUnit_Framework_TestCase
{
    // ...
    public function provideSave()
    {
        return [
            [true, 'saved'],
            [false, 'not saved'],
        ];
    }

    /**
     * @dataProvider provideSave
     */
    public function testSave($succeed, $echoed)
    {
        // mock
        $userMock = test::double('App\User', ['save' => $succeed]);

        ob_start();
        $this->myController->save();
        $content = ob_get_clean();
        $this->assertEquals($echoed, $content);

        // stub
        $userMock->verifyInvoked('save');
    }
    // ...
}

Done 😉

references:
https://github.com/Codeception/AspectMock
https://twitter.com/grmpyprogrammer/status/642847787713884160
https://littlehart.net/atthekeyboard/2014/12/14/stop-telling-me-to-refactor/

Advertisements

PHPUnit: Testing Closure passed to Collaborator

Posted in Teknologi, Tutorial PHP by samsonasik on October 4, 2015

Yes! Closure is callable, so you can just call __invoke() to the closure returned when test it! This is happen when we, for example, have a class and function that have closure inside it like the following:

class Awesome
{
    public function call($foo)
    {
        return function() use ($foo) {
            return $foo;
        };
    }
}

This can be tested with:

use Awesome;
use PHPUnit_Framework_TestCase;

class AwesomeTest extends PHPUnit_Framework_TestCase
{
    protected function setUp()
    {
        $this->awesome = new Awesome();
    }

    public function testCall()
    {
        $foo = 'foo';
        $call = $this->awesome->call($foo);
        $this->assertTrue(is_callable($call));

        $invoked = $call->__invoke();
        $this->assertEquals($foo, $invoked);
    }
}

We need an __invoke() call, as the closure never executed before it invoked. So, we need to call that.

On Collaborator Case

The problem is when we have a collaborator, and closure is processed inside the collaborator:

class Awesome
{
    private $awesomeDependency;

    public function __construct(AwesomeDependency $awesomeDependency)
    {
        $this->awesomeDependency = $awesomeDependency;
    }

    public function call($foo)
    {
        $closure = function() use ($foo) {
            return $foo;
        };
        return $this->awesomeDependency->call($closure);
    }
}

and the closure inside call only executed in the AwesomeDependency class:

class AwesomeDependency
{
    public function call($call)
    {
        return $call();
    }
}

Our test can be like the following:

use Awesome;
use AwesomeDependency;
use PHPUnit_Framework_TestCase;

class AwesomeTest extends PHPUnit_Framework_TestCase
{
    protected function setUp()
    {
        $this->awesomeDependency = $this->prophesize(AwesomeDependency::class);
        $this->awesome     = new Awesome($this->awesomeDependency->reveal());
    }

    public function testCall()
    {
        $foo = 'foo';
        $closure = function() use ($foo) {
            return $foo;
        };

        $this->awesomeDependency
             ->call($closure)
             ->will(function() use ($closure) {
                return $closure->__invoke();
             })
             ->shouldBeCalled();

        $call = $this->awesome->call($foo);
    }
}

As we can see, the $this->awesomeDependency is act as a mock, and calling __invoke() in will() is represent a $closure that already passed to the mock, not the original $closure one, and we will get partial coverage:

closure-call-collaborator1

We know now, it won’t coverable as completed! What we can do? A refactor! But wait, it may be a legacy code, an aggressive refactor may cause problem, so a little but works patch may work for it.

  • Make a $closure as class property, and add mutator and accessor for it.
class Awesome
{
    private $closure;

    // ...

    public function setClosure($closure)
    {
        $this->closure = $closure;
    }

    public function getClosure()
    {
        return $this->closure;
    }

    // ...
}
  • Set $closure property when call call() function:
class Awesome
{
    // ...
    public function call($foo)
    {
        $this->setClosure(function() use ($foo) {
            return $foo;
        });

        return $this->awesomeDependency->call($this->getClosure());
    }
}
  • And in tests, we can now has:
class AwesomeTest extends PHPUnit_Framework_TestCase
{
    // ...
    public function testCall()
    {
        $foo = 'foo';
        $closure = function() use ($foo) {
            return $foo;
        };
        $awesome = $this->awesome;

        $this->awesomeDependency
             ->call($closure)
             ->will(function() use ($awesome) {
                return $awesome->getClosure()->__invoke();
            })
            ->shouldBeCalled();

        $call = $this->awesome->call($foo);
        $this->assertEquals($foo, $call);
    }
}

closure-call-collaborator2

Need a better way? We can replace a closure with an array callback, so, we add additional function that called via call_user_func_array():

class Awesome
{
    public function call($foo)
    {
        return $this->awesomeDependency->call(call_user_func_array(
            [$this, 'onFoo'],
            [$foo]
        ));
    }

    public function onFoo($foo)
    {
        return function() use ($foo) {
            return $foo;
        };
    }
}

And in our tests, we can do:

    public function testCall()
    {
        $foo = 'foo';
        $closure = function() use ($foo) {
            return $foo;
        };
        $awesome = $this->awesome;
        $this->awesomeDependency->call($closure)
             ->will(function() use ($awesome, $foo) {
                 return $awesome->onFoo($foo)->__invoke();
             })
            ->shouldBeCalled();

        $call = $this->awesome->call($foo);
        $this->assertEquals($foo, $call);
    }

And, we now have a fully coverage too:

closure-call-collaborator3

Tagged with: ,

Re-fill selectize js value

Posted in Javascript, Teknologi by samsonasik on November 28, 2014

It’s been a while since I didn’t write a post about non-framework category. Ok, this time, I will show you how to use selectize js on re-fill functionality. Selectize js is a jQuery plugin that useful for tagging and autocomplete. I used it in several projects. Once it’s installed and selectize() called, your form can be like the following :
selectize-1
In images demo above, I want to re-set the “district” based on the “province” changes by javascript. To make selectize still applied to “district”, you need to do :

  • re-set Html option values
  • re-set selectize value options

Ok, let’s do a demo application for this.
1. Preparation
1.a make bower.json for dependency requirements definition

{
    "name":"Selectize Demo",
    "dependencies": {
        "jquery": "1.11.1",
        "selectize":"0.11.2"
    }
}

1.b make .bowerrc for specification

{
    "directory": "js",
    "json": "bower.json"
}

1.c install dependencies

bower install

2. Initialize selectize
We can initialize selectize js by include it in the header ( js and css ) like this :

    <link href="./js/selectize/dist/css/selectize.default.css" media="screen" rel="stylesheet" type="text/css">

    <script type="text/javascript" src="./js/jquery/dist/jquery.min.js"></script>
    <script type="text/javascript" src="./js/selectize/dist/js/standalone/selectize.min.js"></script>

and then, we create the elements which we want to selectize :

<form method="post">

     <select name="province_id" id="province_id">
            <option value="0">--Select Province--</option>
            <option value="1">Jawa Barat</option>
            <option value="2">Jawa Tengah</option>
      </select>

      <select name="district" id="district">
            <option value="0">--Select District--</option>
      </select>

</form>

Now, time to execute :


        $(document).ready(function() {
            //initialize selectize for both fields
            $("#province_id").selectize();
            $("#district").selectize();
        });  

3. Do the awesome
Ok, now what ? We need to re-fill the “district” data on change of “province”, In this case, I wrote a case when using Ajax request and catched by PHP script. So, create a “change-data.php” file :

<?php

if (isset($_POST['province_id'])) {

    $data = [];
    if ($_POST['province_id'] == 1) {
        $data = [
            0 => [
                'id' => 1,
                'name' => 'Bandung',
            ],
            1 => [
                'id' => 2,
                'name' => 'Cimahi',
            ]
        ];
    }

    if ($_POST['province_id'] == 2) {
        $data = [
            0 => [
                'id' => 3,
                'name' => 'Kudus',
            ],
            1 => [
                'id' => 4,
                'name' => 'Cirebon',
            ]
        ];
    }

    echo json_encode($data);
}

Basically, the selectize can be filled by json object that have “text” and “value” key, like the following :

[
    {text: "Bandung", value: 1 },
    {text: "Cimahi", value: 2 }
]

So, we need to get the data, and convert to json object, we can do with eval :

new_value_options = eval('(' + new_value_options + ')');

Ok, now, let’s do this :

$(document).ready(function() {
            //initialize selectize for both fields
            $("#province_id").selectize();
            $("#district").selectize();

            // onchange
            $("#province_id").change(function() {
                $.post('./change-data', { 'province_id' : $(this).val() } , function(jsondata) {
                    var htmldata = '';
                    var new_value_options   = '[';
                    for (var key in jsondata) {
                        htmldata += '<option value="'+jsondata[key].id+'">'+jsondata[key].name+'</option>';

                        var keyPlus = parseInt(key) + 1;
                        if (keyPlus == jsondata.length) {
                            new_value_options += '{text: "'+jsondata[key].name+'", value: '+jsondata[key].id+'}';
                        } else {
                            new_value_options += '{text: "'+jsondata[key].name+'", value: '+jsondata[key].id+'},';
                        }
                    }
                    new_value_options   += ']';

                    //convert to json object
                    new_value_options = eval('(' + new_value_options + ')');
                    if (new_value_options[0] != undefined) {
                        // re-fill html select option field 
                        $("#district").html(htmldata);
                        // re-fill/set the selectize values
                        var selectize = $("#district")[0].selectize;

                        selectize.clear();
                        selectize.clearOptions();
                        selectize.renderCache['option'] = {};
                        selectize.renderCache['item'] = {};

                        selectize.addOption(new_value_options);

                        selectize.setValue(new_value_options[0].value);
                    }

                }, 'json');
            });
        });

That’s it, hope it helpful. Want to grab the code ? grab it from https://github.com/samsonasik/selectize-demo

Tagged with: ,

Zend Framework 2 : Reset HeadTitle Position from View

Posted in Teknologi, Tutorial PHP, Zend Framework 2 by samsonasik on July 14, 2013

zf2-zendframework2Sometime, we need to reset position of title that default we can look at ZendSkeletonApplication like “My Album – ZF2 Skeleton Application” to something like “ZF2 Skeleton Application – My Album”.
We CAN NOT do this from view :

$this->headTitle($title, 'PREPEND');
//OR
$this->headTitle($title, 'APPEND');

because of the layout rendered after view rendered, so we need to pass a value from view to layout via placeholder. So after set a title at view, we need to pass a value via placeholder view helper.

// module/Album/view/album/album/index.phtml:
$title = 'My albums';
$this->headTitle($title);
$this->placeholder('titleType')->set('PREPEND');

so we can set the title type at layout like the following :

// module/Application/view/layout/layout.phtml:
echo $this->headTitle('ZF2 Skeleton Application', 
        $this->placeholder('titleType', 'APPEND'))
          ->setSeparator(' - ')->setAutoEscape(false);

$this->placeholder(‘titleType’, ‘APPEND’) that passed at 2nd parameter of headTitle() means that if titleType already set, so get from the already data, if no, set to ‘APPEND’ as default value.

When situation need to remove layout title ( parameter is ‘SET’), and use the view title, we need to make a conditional like this :

// module/Application/view/layout/layout.phtml:
if ($this->placeholder('titleType', 'APPEND') == 'SET') { 
    echo $this->headTitle()->setAutoEscape(false);
} else {
   echo $this->headTitle('ZF2 Skeleton Application', 
          $this->placeholder('titleType', 'APPEND'))
             ->setSeparator(' - ')->setAutoEscape(false);
}

That’s it 😉

references:
1. http://stackoverflow.com/questions/13949809/zend-framework-2-make-content-page-variable-accessable-in-layout-phtml
2. http://zf2.readthedocs.org/en/latest/modules/zend.view.helpers.placeholder.html#zend-view-helpers-initial-placeholder

Zend Framework 2 : Generate Doctrine Entities from Existing Database using DoctrineModule and DoctrineORMModule

Posted in orm, Teknologi, Tutorial PHP, Zend Framework 2 by samsonasik on April 10, 2013

zf2-zendframework2If we are working with Doctrine , we usually create entities first, and generate the database tables. How if the situation is the database tables and data is already ready, and we have to create an application based on doctrine and Zend Framework 2? We need generate entities! Don’t create them manually!
For example, i have two tables : album and track (i’m using PostgreSQL ) like the following :

-- Table: album
CREATE TABLE album
(
  id bigserial NOT NULL,
  artist character varying(255),
  title character varying(255),
  CONSTRAINT pk_album PRIMARY KEY (id )
)
WITH (
  OIDS=FALSE
);
ALTER TABLE album
  OWNER TO developer;

-- Table: track
CREATE TABLE track
(
  track_id bigserial NOT NULL,
  track_title character varying(255),
  album_id bigint,
  CONSTRAINT track_pkey PRIMARY KEY (track_id ),
  CONSTRAINT fk_track_album FOREIGN KEY (album_id)
      REFERENCES album (id) MATCH SIMPLE
      ON UPDATE CASCADE ON DELETE CASCADE
)
WITH (
  OIDS=FALSE
);
ALTER TABLE track
  OWNER TO developer;

Ok, let’s create an application based on ZF2 step by step :
1. install ZF2 SkeletonApplication

git clone git://github.com/zendframework/ZendSkeletonApplication.git zftutordoctrine

2. add “doctrine/doctrine-orm-module” to your zftutordoctrine/composer.json

{
    "name": "zendframework/skeleton-application",
    "description": "Skeleton Application for ZF2",
    "license": "BSD-3-Clause",
    "keywords": [
        "framework",
        "zf2"
    ],
    "homepage": "http://framework.zend.com/",
    "require": {
        "php": ">=5.3.3",
        "zendframework/zendframework": ">2.1.3",
        "doctrine/doctrine-orm-module": "0.*"
    }
}

3. Install it

php composer.phar self-update && php composer.phar install

4. Create an Album module with structure entity like the following :
5-albumomodule-structure
5. Configure doctrine connection
You can define it at one file, but separate it with two file(local and global) can make security happy 😀
a. config/autoload/doctrine.global.php

//config/autoload/doctrine.global.php
return array(
    'doctrine' => array(
        'connection' => array(
            'orm_default' => array(
                'driverClass' => 'Doctrine\DBAL\Driver\PDOMySql\Driver',
                    'params' => array(
                        'host' => 'localhost',
                        'port' => '5432',
                        'dbname' => 'zftutordoctrine',
                ),
            ),
        )
));

b. config/autoload/doctrine.local.php

//config/autoload/doctrine.local.php
return array(
    'doctrine' => array(
        'connection' => array(
            'orm_default' => array(
                'driverClass' => 'Doctrine\DBAL\Driver\PDOPgSql\Driver',
                    'params' => array(
                        'user' => 'developer',
                        'password' => '123456',
                ),
            ),
        )
));

6. register Album\Entity into doctrine driver in module/Album/config/module.config.php

//module/Album/config/module.config.php
return array(
    'doctrine' => array(
        'driver' => array(
            'Album_driver' => array(
                'class' => 'Doctrine\ORM\Mapping\Driver\AnnotationDriver',
                'cache' => 'array',
                'paths' => array(__DIR__ . '/../src/Album/Entity')
            ),
            'orm_default' => array(
                'drivers' => array(
                     'Album\Entity' =>  'Album_driver'
                ),
            ),
        ),
    ),                 
);

7. Register modules into config/application.config.php

//config/application.config.php
return array(
    'modules' => array(
        'Application',
        'DoctrineModule',
        'DoctrineORMModule',
        'Album'
    ),
    
    // These are various options for the listeners attached to the ModuleManager
    'module_listener_options' => array(
        'module_paths' => array(
            './module',
            './vendor',
        ),
        'config_glob_paths' => array(
            'config/autoload/{,*.}{global,local}.php',
        ),
    ),
);

8. Generate Time !
a. convert-mapping

./vendor/doctrine/doctrine-module/bin/doctrine-module orm:convert-mapping --namespace="Album\\Entity\\" --force  --from-database annotation ./module/Album/src/

it will export “annotation” mapping information into ./module/Album/src/
b. generate-entities

 ./vendor/doctrine/doctrine-module/bin/doctrine-module orm:generate-entities ./module/Album/src/ --generate-annotations=true

it will add setter/getter into entities.
and you will get the following entities AUTOMATICALLY :
Album\Entity\Album

<?php

namespace Album\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Album
 *
 * @ORM\Table(name="album")
 * @ORM\Entity
 */
class Album
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="bigint", nullable=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="SEQUENCE")
     * @ORM\SequenceGenerator(sequenceName="album_id_seq", allocationSize=1, initialValue=1)
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="artist", type="string", length=255, nullable=true)
     */
    private $artist;

    /**
     * @var string
     *
     * @ORM\Column(name="title", type="string", length=255, nullable=true)
     */
    private $title;



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

    /**
     * Set artist
     *
     * @param string $artist
     * @return Album
     */
    public function setArtist($artist)
    {
        $this->artist = $artist;
    
        return $this;
    }

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

    /**
     * Set title
     *
     * @param string $title
     * @return Album
     */
    public function setTitle($title)
    {
        $this->title = $title;
    
        return $this;
    }

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

Album\Entity\Track

<?php

namespace Album\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Track
 *
 * @ORM\Table(name="track")
 * @ORM\Entity
 */
class Track
{
    /**
     * @var integer
     *
     * @ORM\Column(name="track_id", type="bigint", nullable=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="SEQUENCE")
     * @ORM\SequenceGenerator(sequenceName="track_track_id_seq", allocationSize=1, initialValue=1)
     */
    private $trackId;

    /**
     * @var string
     *
     * @ORM\Column(name="track_title", type="string", length=255, nullable=true)
     */
    private $trackTitle;

    /**
     * @var \Album\Entity\Album
     *
     * @ORM\ManyToOne(targetEntity="Album\Entity\Album")
     * @ORM\JoinColumns({
     *   @ORM\JoinColumn(name="album_id", referencedColumnName="id")
     * })
     */
    private $album;



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

    /**
     * Set trackTitle
     *
     * @param string $trackTitle
     * @return Track
     */
    public function setTrackTitle($trackTitle)
    {
        $this->trackTitle = $trackTitle;
    
        return $this;
    }

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

    /**
     * Set album
     *
     * @param \Album\Entity\Album $album
     * @return Track
     */
    public function setAlbum(\Album\Entity\Album $album = null)
    {
        $this->album = $album;
    
        return $this;
    }

    /**
     * Get album
     *
     * @return \Album\Entity\Album 
     */
    public function getAlbum()
    {
        return $this->album;
    }
}

JUST IMAGINE that YOU SHOULD WRITE THEM MANUALLY :p
9. Fill database tables rows, and Let’s call from whatever controller for testing :

    public function indexAction()
    {
        $em = $this->getServiceLocator()
                ->get('doctrine.entitymanager.orm_default');
        $data = $em->getRepository('Album\Entity\Track')->findAll();
        foreach($data as $key=>$row)
        {
            echo $row->getAlbum()->getArtist().' :: '.$row->getTrackTitle();
            echo '<br />';
        }
    }

References :
1. Conversation with Anass Ans
1. http://docs.doctrine-project.org/en/2.0.x/reference/tools.html
2. http://wildlyinaccurate.com/useful-doctrine-2-console-commands

Practical GIT (3) : Remove Specific commits

Posted in GIT, Teknologi by samsonasik on February 24, 2013

git-logo If you’are working with pilot project that many feature are experiment conditions, you need this feature, You can remove commits that you don’t want to exist in your revisions log. This feature named rebase. You can find the whole commits lists on range by typing :

git rebase -i HEAD~5

that command will show you last 5 commit and show them in the editor like the following :

pick 5c22314 third commit
pick 8de60b5 fourth commit
pick 9d3556f fifth commit
pick 434ddc3 sixth commit
pick d9b917g seventh commit

# Rebase d9b917f..8de60b5 onto d9b917f
#
# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#  f, fixup = like "squash", but discard this commit's log message
#  x, exec = run command (the rest of the line) using shell
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#
~

~

If you want to remove fifth and sixth commit, just remove these two lines and save the editor ( if you’re working with vim, type ‘dd’ in the line you want to delete, and type ‘:wq!’. After do that, check by typing command :

git log

and you will get the result like the following ( fifth and sixth commit deleted ! )

commit d9b917g9d3556cfb0d0bbcd8ecd952cf4f358eea
Author: Abdul Malik Ikhsan <samsonasik@gmail.com>
Date:   Wed Feb 20 15:47:13 2013 +0700

    seventh commit

commit 8de60b59d3556cd8eeafb0d0bbcd8ec952cf4f35
Author: Abdul Malik Ikhsan <samsonasik@gmail.com>
Date:   Wed Feb 20 15:47:13 2013 +0700

    fourth commit

commit 5c223149d3556cd952cf4f358eeafb0d0bbcd8ec
Author: Abdul Malik Ikhsan <samsonasik@gmail.com>
Date:   Wed Feb 20 15:47:13 2013 +0700

    third commit

commit 5c2231434ddc3bac911ab38a22d2b47f5736f7d4
Author: Abdul Malik Ikhsan <samsonasik@gmail.com>
Date:   Wed Feb 20 15:46:50 2013 +0700

    second commit

commit d9b917f6a48eb9c0c415772f70b7c66adf3de0b5
Author: Abdul Malik Ikhsan <samsonasik@gmail.com>
Date:   Wed Feb 20 15:45:26 2013 +0700

    first commit

With rebase, you can combine commits to/from other branch or squash commits with commands list while you get the list of commit via rebase -i command.

references :
1. http://www.kernel.org/pub/software/scm/git/docs/git-rebase.html

Rsync : Synchronize local with shared hosting

Posted in Teknologi, tips and tricks by samsonasik on January 26, 2013

rsyncAs web developer, We already realize that we are lazy. Our client is often only have shared hosting, not dedicated server that we can install version control which simplify push and pull. We often forgot to upload some file we changed/added in local to shared hosting, and it make web is not run properly in shared hosting.  The solution is to use rsync in local PC.  Rsync is a file transfer program for Unix systems. rsync uses the ‘rsync algorithm’ which provides a very fast method for bringing remote files into sync. An important feature of rsync not found in most similar programs/protocols is that the mirroring takes place with only one transmission in each direction. Rsync can copy or display directory contents and copy files, optionally using compression and recursion.
So, you need to know the step to do this :
1. Go to your Cpanel
2. Click Ftp Account
Screen Shot 2013-01-26 at 4.36.40 PM
3. Click Configure FTP Client in your desired user
Screen Shot 2013-01-26 at 4.39.14 PM

And see the SFTP Port. Use the port to in rsync port target transfer.
4. Start syncing…

cd ~/www && rsync -timeout=50000 -av --exclude ".git" --exclude ".gitignore" --exclude "wp-config.php"  wordpress_local_dev/ -e "ssh -p 2223" yourremoteserveruser@yourdomain.com:/home/yourremoteserveruser/public_html/

The option –exclude will exclude unneeded to sync.
The option -timeout is what second to be connection to timeout.
And you will see the following ( just updated / added file will be uploaded ) :

5. Done !

References :
Image : http://www.haykranen.nl/wp-content/uploads/2008/05/timemachine.jpg
Source :
1. http://mike-hostetler.com/blog/2007/12/08/rsync-non-standard-ssh-port/
2. http://en.wikipedia.org/wiki/Rsync

Zend Framework 2 ‘Cheat Sheet’ : Service Manager

Posted in Teknologi, Tutorial PHP, Zend Framework 2 by samsonasik on January 2, 2013

zf2-zendframework2The Service Locator design pattern is implemented by the ServiceManager. The Service Locator is a service/object locator, tasked with retrieving other objects.

Get the SM :
1. Inside Controller

$serviceLocator = $this->getServiceLocator();

2. Inside Module.php

namespace YourModule\Service;

use Zend\Mvc\MvcEvent;

class Module
{
    public function onBootstrap(MvcEvent $e)
    {
        $sm = $e->getApplication()->getServiceManager();
    }
}

3. Inside Controller Plugin

$serviceLocator = $this->getController()->getServiceLocator();

Types of Services
The registered name of service is not case sensitive. There are the type of services :
a. invokables : an array of service name/class name pairs. The class name should be class that may be directly instantiated without any constructor arguments
for ex :

//YourModule/config/module.config.php
return array(
    'controllers'=>array(
        'invokables' => array(
            'SanUser\Controller\User' => 'SanUser\Controller\UserController'
        ),
    ),
);

b. abstract_factories : Unknown Services ( The “Limbo” if ServiceManager failed to search in registered services)

//YourModule/src/YourModule/Service/CommonControlAppAbstractFactory.php
namespace YourModule\Service;

use Zend\ServiceManager\AbstractFactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;

class CommonControlAppAbstractFactory implements AbstractFactoryInterface
{
    public function canCreateServiceWithName(ServiceLocatorInterface $locator, $name, $requestedName)
    {
        if (class_exists($requestedName.'Controller')){
            return true;
        }

        return false;
    }

    public function createServiceWithName(ServiceLocatorInterface $locator, $name, $requestedName)
    {
        $class = $requestedName.'Controller';
        return new $class;
    }
}

Then, register in SM :

//YourModule/config/module.config.php
return array(
    'controllers'=> array(
	    'abstract_factories' => array(
		'YourModule\Service\CommonControlAppAbstractFactory',
	    ),
	);
    ),
);

In this case, if SM could not find controllers in invokables, the SM will turn to it whenever canCreateServiceWithName return true; ( controllers is service that called automatically by mvc stack )
What if you want other service ? This is it :

namespace YourModule\Service;

use Zend\ServiceManager\AbstractFactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;

class CommonModelTableAbstractFactory implements AbstractFactoryInterface
{
    public function canCreateServiceWithName(ServiceLocatorInterface $locator, $name, $requestedName)
    {
        return (substr($requestedName, -5) === 'Table');
    }

    public function createServiceWithName(ServiceLocatorInterface $locator, $name, $requestedName)
    {
        $db = $locator->get('Zend\Db\Adapter\Adapter');
        $tablemodel = new $requestedName;
        $tablemodel->setDbAdapter($db);
        
        return $tablemodel;
    }
}

You want if you call un-registered table model, you automatically create service with this abstract factory whenever last 5 chars of the service called = ‘Table’. Register this abstract factory under service_manager key :

//YourModule/config/module.config.php
return array(
    'service_manager'=> array(
	    'abstract_factories' => array(
		'YourModule\Service\CommonModelTableAbstractFactory',
	    ),
	);
    ),
);

Note for abstract_factories : Being explicit is more secure and reliable. You should not forgot to register service you write into ServiceManager.

c. factories : an array of service name/factory class name pairs.
c.1. If you are using PHP configuration files, you may provide any PHP callable as the factory.

//YourModule/config/module.config.php
return array(
    'service_manager'=>array(
        'factories' => array(
            'MyTable' => function ($sm) {
                $db = $sm->get('Zend\Db\Adapter\DbAdapter');
                $table = new \YourModule\Model\MyTableModel();
                $table->setDbAdapter($db);
            },
        ),
    ),
);

c.2. by implementing Zend\ServiceManager\FactoryInterface by create a factory first :

namespace YourModule\Service;

use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;

class MyTableFactory implements FactoryInterface
{
    public function createService(ServiceLocatorInterface $serviceLocator)
    {
        $db = $serviceLocator->get('Zend\Db\Adapter\DbAdapter');
        $table = new \YourModule\Model\MyTableModel();
        $table->setDbAdapter($db);

        return $table;
    }
}

And the factories registered just like the following :

//YourModule/config/module.config.php
return array(
    'service_manager'=>array(
        'factories' => array(
            'MyTable' => 'YourModule\Service\MyTableFactory'
        ),
    ),
);

d. aliases : which should be an associative array of alias name/target name pairs (where the target name may also be an alias).

//YourModule/config/module.config.php
return array(
    'service_manager'=>array(
        'factories' => array(
            'MyTable' => 'YourModule\Service\MyTableFactory'
        ),
        'aliases' => array(
            'YourModule\Model\MyTable' => 'MyTable',
        ),
    ),
);

e. shared :an array of service name/boolean pairs, indicating whether or not a service should be shared. By default, the ServiceManager assumes all services are shared, but you may specify a boolean false value here to indicate a new instance should be returned.

//YourModule/config/module.config.php
return array(
    'service_manager'=>array(
        'factories' => array(
            'MyTable' => 'YourModule\Service\MyTableFactory'
        ),
        'shared' => array(
            // Usually, you'll only indicate services that should _NOT_ be
            // shared -- i.e., ones where you want a different instance
            // every time.
            'MyTable' => false,
        ),
    ),
);

f. services : an array of service name/object pairs. Clearly, this will only work with PHP configuration.

//YourModule/config/module.config.php
return array(
    'service_manager'=>array(
        'services' => array(
            // Keys are the service names
            // Values are objects
            'Auth' => new YourModule\Authentication\AuthenticationService(),
        ),
    ),
);

g. initializers
It initialize the service whenever service created. It can reduce the redundance the injections to services.

//YourModule/config/module.config.php
return array(
    'service_manager'=>array(
        'initializers' => array(
	    function ($instance, $sm) {
		if ($instance instanceof \Zend\Db\Adapter\AdapterAwareInterface) {
		    $instance->setDbAdapter($sm->get('Zend\Db\Adapter\Adapter'));
		}
	    }
	),
    ),
);

And you should not to inject Adapter manually in the Table Class :

namespace YourModule\Model;

use Zend\Db\TableGateway\AbstractTableGateway;
use Zend\Db\Adapter\AdapterAwareInterface;
use Zend\Db\Adapter\Adapter;

class UserTable extends AbstractTableGateway
    implements AdapterAwareInterface
{
    protected $table = 'zf2_users';

    public function setDbAdapter(Adapter $adapter)
    {
        $this->adapter = $adapter;
        $this->initialize();
    }
}

Just invoke at service_manager :

//YourModule/config/module.config.php
return array(
    'service_manager'=>array(
        'initializers' => array(
	    function ($instance, $sm) {
		if ($instance instanceof \Zend\Db\Adapter\AdapterAwareInterface) {
		    $instance->setDbAdapter($sm->get('Zend\Db\Adapter\Adapter'));
		}
	    }
	),
        'invokables' => array(
            'YourModule\Model\UserTable' => 'YourModule\Model\UserTable'
        )
    ),
);

h. allow_override
Override your existing Services.

//YourModule/config/module.config.php
return array(
    'service_manager'=>array(
        'factories' => array(
            'MyService' => 'YourModule\Service\MyServiceFactory'
        ),
        'allow_override' => array(
            'MyService' => true,
        ),
    ),
);

The top level configuration keys

Manager Key name in configuration array Method name in Module.php
ServiceManager service_manager getServiceConfig()
ViewHelperManager view_helpers getViewHelperConfig()
ControllerPluginManager controller_plugins getControllerPluginConfig()
ControllerLoader controllers getControllerConfig()

Sample Code in Module.php :

class Module
{
    //for 'service_manager'
    public function getServiceConfig()
    {
        return array(
            'invokables' => array( /* see Types of Services */  ),
            'factories' => array( /* see Types of Services */ ),
            'abstract_factories' => array( /* see Types of Services */ ),
            'aliases' => array( /* see Types of Services */ ),
            'services' => array( /* see Types of Services */ ),
            'initializers' => array( /* see Types of Services */ ),
            'shared' => array(/* see Types of Services */),
        );
    }

    //for 'controllers' -> it automatically composed by mvc stack
    //no need to call by your hand ( get('...') );
    public function getControllerConfig()
    {
        return array(
            /* looks like above code */
        );
    }

    //for 'controller_plugins'
    public function getControllerPluginConfig()
    {
        return array(
            /* looks like above code */
        );
    }

    //for 'view_helpers' call in view by $this->nameViewHelperRegistered()->dosomething()
    public function getViewHelperConfig()
    {
        return array(
            /* looks like above code */
        );
    }
}

For ZF 2.1 ( still in dev branch, the keys added with FormElementManager )

Manager Key name in configuration array Method name in Module.php
FormElementManager form_elements getFormElementConfig()

For what have to do to create a Controller pLugin , see : empirio’s post about creating Controller pLugin in ZF2. For what have to do to create a View Helper , see : my post about creating view helper or EvanDotPro’s post.

Hope this post helpful ;). Happy new Year!

References :
1. http://zf2.readthedocs.org/en/latest/modules/zend.service-manager.intro.html
2. http://akrabat.com/zend-framework-2/zendservicemanager-configuration-keys/
3. http://juriansluiman.nl/en/article/120/using-zend-framework-service-managers-in-your-application
4. http://blog.evan.pro/creating-a-simple-view-helper-in-zend-framework-2
5. http://lab.empirio.no/custom-controller-plugin-in-zf2.html

Practical GIT (2) : Update remote file after push with configure post-receive hooks

Posted in GIT, Teknologi by samsonasik on November 20, 2012

GIT version control got one feature that I really like, named hooks. With hooks, we can configure what GIT do after metadata pushed to the remote server. It can ease our development because we don’t need to upload file manually, just say : git push remoteserver, so the file in our online web will be replaced.

Continue Reading

Tagged with: , ,

Zend Framework 2 : Step by Step create RESTful Application

Posted in Teknologi, Tutorial PHP, Zend Framework 2 by samsonasik on October 31, 2012

Beside AbstractActionController, ZF2 has AbstractRestfulController that provide RESTful implementation that simply maps HTTP request methods to controller methods : GET maps to either get() or getList(), POST maps to create(), PUT maps to update(), and DELETE maps to delete().

Continue Reading

Zend Framework 2 : Using Zend\Cache and HydratingResultSet to Save Database Resultset into Cache

Posted in Teknologi, Tutorial PHP, Zend Framework 2 by samsonasik on September 27, 2012

Re-load data from the database every web was accessed is not good for your server ‘health’. Zend Framework has a component named Hydrator. The Hydrator is a simple component to provide mechanisms both for hydrating objects, as well as extracting data sets from them.
To save database ResultSet into cache, You need to use Zend\Db\ResultSet\HydratingResultSet which can extract the resultSet into associative array. In this post, i will show you how to cache your database resultset into filesystem.

Continue Reading

Zend Framework 2 : Create Custom Error Page

Posted in Teknologi, Tutorial PHP, Zend Framework 2 by samsonasik on September 19, 2012

In production Application Environment, we should handle error page that user will be viewed. In Zend Framework 2, we can create our custom error page which show the user that the page is error, but not show them the exception.

Continue Reading

Zend Framework 2 : Setting Default Db Adapter

Posted in Teknologi, Tutorial PHP, Zend Framework 2 by samsonasik on August 28, 2012

The price of flexibility in Zend Framework 2 often push us to setting all ‘manually’. We have to be a creative person, right ? In this post, i want to present you my greatest post ! Simple, but very important because it can reduce your code redundancy in setting up DbAdapter to Your Table Class.

Continue Reading

Zend Framework 2 : ZendDeveloperTools : The ZF2 tools You must install

Posted in Teknologi, Tutorial PHP, Zend Framework 2 by samsonasik on August 7, 2012

ZendDeveloperTools is a Module for developer and debug tools for working with the ZF2 MVC layer. It can show you a request method, response code, current controller/action, current route we access, execution time, memory consumption, grab the profiler of Zend\Db adapter instance, and Zend Framework version you currently use.

Continue reading …