- 2014/03/22

Saya kadang membutuhkan current route yang sedang saya akses di view script, misalnya untuk navigasi, atau keperluan yang lain. Zend Framework 2 tidak mempunyai helper untuk mengakses hal tersebut, karena memang rekomendasinya adalah “bukan penerapan yang baik” jika mengakses dari view. Tapi ada pendapat juga yang mengatakan bahwa “ambil RouteMatch dari factory dan gunakan yang diperlukan di view helper”. Jika anda masih membayangkan bagaimana penerapan hal tersebut, bisa dilihat pada gambar dibawah ini :

Pada gambar diatas, kotak hijau adalah currentRoute yang sedang diakses, sedangkan kotak merah adalah route yang sedang tidak diakses. Pencocokan currentRoute saya gunakan untuk menentukan style yang dipakai oleh tab tersebut, jika currentRoute sesuai, maka diberikan nilai “active” pada list class-nya.

Baiklah, sekarang saya bagikan kode view helper dan factory yang saya pakai untuk kasus seperti tersebut diatas. Class ini simpel sekali, hanya membutuhkan \Zend\Mvc\Router\Http\RouteMatch() dan \Zend\Mvc\MvcEvent::isError() yang diberikan pada pembuatan object di class Factory.

<?php
/**
 * Simukti\View\Helper\CurrentRoute
 *
 * Sarjono Mukti Aji <[email protected]>
 */
namespace Simukti\View\Helper;
 
use Zend\View\Helper\AbstractHelper;
use Zend\Mvc\Router\Http\RouteMatch;
 
class CurrentRoute extends AbstractHelper
{
    /**
     * Status apakah request error atau tidak
     * 
     * @var boolean
     */
    protected $isError;
    
    /**
     * @var RouteMatch
     */
    protected $routeMatch;
    
    /**
     * @return  boolean
     */
    public function getIsError()
    {
        return $this->isError;
    }
 
    /**
     * @param   boolean $isError
     * @return  \Simukti\View\Helper\CurrentRoute
     */
    public function setIsError($isError)
    {
        $this->isError = $isError;
        return $this;
    }
 
    /**
     * @return  \Zend\Mvc\Router\Http\RouteMatch
     */
    public function getRouteMatch()
    {
        return $this->routeMatch;
    }
 
    /**
     * @param   \Zend\Mvc\Router\Http\RouteMatch $routeMatch
     * @return  \Simukti\View\Helper\CurrentRoute
     */
    public function setRouteMatch(RouteMatch $routeMatch = null)
    {
        $this->routeMatch = $routeMatch;
        return $this;
    }
    
    /**
     * Periksa apakah nama route yang sedang diakses sama.
     * Atau ambil nama route yang sedang diakses.
     * 
     * @param   string  $route_name     default null
     * @return  boolean|string|array
     */
    public function __invoke($route_name = null) 
    {
        if (null === $route_name) {
            return $this->getRouteMatch()->getMatchedRouteName();
        }
        
        return $this->isRouteNameMatch($route_name);
    }
    
    /**
     * @param   string|array $route_name
     * @return  boolean
     */
    protected function isRouteNameMatch($route_name)
    {
        if($this->getIsError()) {
            return false;
        }
        
        $routeMatch     = $this->getRouteMatch();
        $matchedRoute   = $routeMatch->getMatchedRouteName();
        
        if(is_array($route_name)) {
            return (in_array($matchedRoute, $route_name)) ? true : false;
        } else {
            return (trim($route_name) === $matchedRoute) ? true : false;
        }
    }
}

Pada class diatas yang berfungsi untuk mencocokkan adalah method isRouteNameMatch($route_name), dan $route_name bisa berupa string nama route atau array berisi nama-nama route. Kemudian untuk Factory yang memanggil class tersebut adalah sebagai berikut :

<?php
/**
 * Simukti\View\Helper\CurrentRouteFactory
 *
 * Sarjono Mukti Aji <[email protected]>
 */
namespace Simukti\View\Helper;
 
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
 
class CurrentRouteFactory implements FactoryInterface
{
    public function createService(ServiceLocatorInterface $services)
    {
        $mvcEvent   = $services->getServiceLocator()
                               ->get('Application')
                               ->getMvcEvent();
                               
        $routeMatch = $mvcEvent->getRouteMatch();
        
        $helper = new CurrentRoute();
        
        // TypeHint routeMatch diset dari sini,
        // karena jika hanya getMatchedRouteName() yang di-set
        // maka akan error apabila halaman yang diakses notFound.
        $helper->setRouteMatch($routeMatch)
               ->setIsError($mvcEvent->isError());
 
        return $helper;
    }
}

Sekarang kita debug script tersebut menggunakan \Zend\Debug\Debug::dump() seperti ini :

<?php 
// misalkan sedang berada pada route name 'home'
//
// string(4) "home"
\Zend\Debug\Debug::dump($this->currentRoute()); 
 
//bool(false)
\Zend\Debug\Debug::dump($this->currentRoute('blog'));
 
// bool(true)
\Zend\Debug\Debug::dump($this->currentRoute('home'));
 
// bool(true)
\Zend\Debug\Debug::dump($this->currentRoute(array('blog', 'contact', 'home'))); 

Cukup jelas kan ? Terus bagaimana saya menggunakan helper tersebut di website ini ? Saya ambil contoh di bagian blog archive dan tags, disitu ada navigasi tab yang menggunakan helper ini, sehingga akan otomatis menambahkan class ‘active’ pada link list yang sedang diakses, seperti pada kode dibawah ini :

<ul class="nav nav-tabs page-nav">
    <li<?php echo ($this->currentRoute('blog')) ? ' class="active"' : '';?>>
        <a href="<?php echo $this->url('blog', array(), array(
            'force_canonical' => true
        )); ?>">
            <i class="fa fa-fw fa-folder-open"></i> Archive
        </a>
    </li>
    <li<?php echo ($this->currentRoute('blog/tag')) ? ' class="active"' : '';?>>
        <a href="<?php echo $this->url('blog/tag', array(), array(
            'force_canonical' => true
        )); ?>">
            <i class="fa fa-fw fa-tags"></i> Tags
        </a>
    </li>
</ul>

Simpel sekali kan? Semoga gambaran tersebut diatas cukup membantu jika anda memerlukan. Bila ada metode lain yang lebih efisien untuk mencocokkan route name daripada cara saya diatas, jangan sungkan untuk mengisi komentar dibawah.