Issues

ZF-10465: Add option 'encodeUrl' to Zend_Page_MVC config

Description

Zend_Page_MVC has the option to switch whether params should be reset when assembling URL. There are some cases where some params contain characters (like '/') which needs to be preserved by some routes. So there needs to be a way of sitching encodeUrl.

E.g.: You have a route for content-pages like this


'content' => array(
    'type' => 'Zend_Controller_Router_Route_Regex',
    'route' => '(.+)\.html',
    'defaults' => array(
        'module' => 'default',
        'controller' => 'content',
        'action' => 'content'
    ),
    'map' => array(
        1 => 'contentKey'
    ),
    'reverse' => '%s.html'
),

And later on you want to define some subpages via Zend_Navigation:


 array(
    'label' => 'PageXY',
    'route' => 'content',
    'module' => 'default',
    'controller' => 'content',
    'action' => 'content',
    'params' => array(
        'contentKey' => 'pagexy/subpage'
    )
),

This results in an invalid href, because Zend_Page_MVC calls a url-helper (Zend_Controller_Action_Helper_Url) internally, but there is no way to pass a configuration variable which controls the parameter '$encode' of url-helper

Comments

I changed the code of class Zend_Navigation_Page_Mvc in my setup, so there is a way to control the url encoding. Maybe there is a way this can be applied to further ZF-Version?

<?php /** * Zend Framework * * LICENSE * * This source file is subject to the new BSD license that is bundled * with this package in the file LICENSE.txt. * It is also available through the world-wide-web at this URL: * http://framework.zend.com/license/new-bsd * If you did not receive a copy of the license and are unable to * obtain it through the world-wide-web, please send an email * to license@zend.com so we can send you a copy immediately. * * @category Zend * @package Zend_Navigation * @subpackage Page * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License * @version $Id: Mvc.php 20096 2010-01-06 02:05:09Z bkarwin $ */

/** * @see Zend_Navigation_Page */ require_once 'Zend/Navigation/Page.php';

/** * @see Zend_Controller_Action_HelperBroker */ require_once 'Zend/Controller/Action/HelperBroker.php';

/** * Used to check if page is active * * @see Zend_Controller_Front */ require_once 'Zend/Controller/Front.php';

/** * Represents a page that is defined using module, controller, action, route * name and route params to assemble the href * * @category Zend * @package Zend_Navigation * @subpackage Page * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License */ class Zend_Navigation_Page_Mvc extends Zend_Navigation_Page { /** * Action name to use when assembling URL * * @var string */ protected $_action;

/**
 * Controller name to use when assembling URL
 *
 * @var string
 */
protected $_controller;

/**
 * Module name to use when assembling URL
 *
 * @var string
 */
protected $_module;

/**
 * Params to use when assembling URL
 *
 * @see getHref()
 * @var array
 */
protected $_params = array();

/**
 * Route name to use when assembling URL
 *
 * @see getHref()
 * @var string
 */
protected $_route;

/**
 * Whether params should be reset when assembling URL
 *
 * @see getHref()
 * @var bool
 */
protected $_resetParams = true;

/**
 * Whether href should be encoded when assembling URL
 *
 * @see getHref()
 * @var bool
 */
protected $_encodeUrl = true;

/**
 * Cached href
 *
 * The use of this variable minimizes execution time when getHref() is
 * called more than once during the lifetime of a request. If a property
 * is updated, the cache is invalidated.
 *
 * @var string
 */
protected $_hrefCache;

/**
 * Action helper for assembling URLs
 *
 * @see getHref()
 * @var Zend_Controller_Action_Helper_Url
 */
protected static $_urlHelper = null;

// Accessors:

/**
 * Returns whether page should be considered active or not
 *
 * This method will compare the page properties against the request object
 * that is found in the front controller.
 *
 * @param  bool $recursive  [optional] whether page should be considered
 *                          active if any child pages are active. Default is
 *                          false.
 * @return bool             whether page should be considered active or not
 */
public function isActive($recursive = false)
{
    if (!$this->_active) {
        $front = Zend_Controller_Front::getInstance();
        $reqParams = $front->getRequest()->getParams();

        if (!array_key_exists('module', $reqParams)) {
            $reqParams['module'] = $front->getDefaultModule();
        }

        $myParams = $this->_params;

        if (null !== $this->_module) {
            $myParams['module'] = $this->_module;
        } else {
            $myParams['module'] = $front->getDefaultModule();
        }

        if (null !== $this->_controller) {
            $myParams['controller'] = $this->_controller;
        } else {
            $myParams['controller'] = $front->getDefaultControllerName();
        }

        if (null !== $this->_action) {
            $myParams['action'] = $this->_action;
        } else {
            $myParams['action'] = $front->getDefaultAction();
        }

        if (count(array_intersect_assoc($reqParams, $myParams)) ==
            count($myParams)) {
            $this->_active = true;
            return true;
        }
    }

    return parent::isActive($recursive);
}

/**
 * Returns href for this page
 *
 * This method uses {@link Zend_Controller_Action_Helper_Url} to assemble
 * the href based on the page's properties.
 *
 * @return string  page href
 */
public function getHref()
{
    if ($this->_hrefCache) {
        return $this->_hrefCache;
    }

    if (null === self::$_urlHelper) {
        self::$_urlHelper =
            Zend_Controller_Action_HelperBroker::getStaticHelper('Url');
    }

    $params = $this->getParams();

    if ($param = $this->getModule()) {
        $params['module'] = $param;
    }

    if ($param = $this->getController()) {
        $params['controller'] = $param;
    }

    if ($param = $this->getAction()) {
        $params['action'] = $param;
    }

    $url = self::$_urlHelper->url($params,
                                  $this->getRoute(),
                                  $this->getResetParams(),
                                  $this->getEncodeUrl()
                                  );

    return $this->_hrefCache = $url;
}

/**
 * Sets action name to use when assembling URL
 *
 * @see getHref()
 *
 * @param  string $action             action name
 * @return Zend_Navigation_Page_Mvc   fluent interface, returns self
 * @throws Zend_Navigation_Exception  if invalid $action is given
 */
public function setAction($action)
{
    if (null !== $action && !is_string($action)) {
        require_once 'Zend/Navigation/Exception.php';
        throw new Zend_Navigation_Exception(
                'Invalid argument: $action must be a string or null');
    }

    $this->_action = $action;
    $this->_hrefCache = null;
    return $this;
}

/**
 * Returns action name to use when assembling URL
 *
 * @see getHref()
 *
 * @return string|null  action name
 */
public function getAction()
{
    return $this->_action;
}

/**
 * Sets controller name to use when assembling URL
 *
 * @see getHref()
 *
 * @param  string|null $controller    controller name
 * @return Zend_Navigation_Page_Mvc   fluent interface, returns self
 * @throws Zend_Navigation_Exception  if invalid controller name is given
 */
public function setController($controller)
{
    if (null !== $controller && !is_string($controller)) {
        require_once 'Zend/Navigation/Exception.php';
        throw new Zend_Navigation_Exception(
                'Invalid argument: $controller must be a string or null');
    }

    $this->_controller = $controller;
    $this->_hrefCache = null;
    return $this;
}

/**
 * Returns controller name to use when assembling URL
 *
 * @see getHref()
 *
 * @return string|null  controller name or null
 */
public function getController()
{
    return $this->_controller;
}

/**
 * Sets module name to use when assembling URL
 *
 * @see getHref()
 *
 * @param  string|null $module        module name
 * @return Zend_Navigation_Page_Mvc   fluent interface, returns self
 * @throws Zend_Navigation_Exception  if invalid module name is given
 */
public function setModule($module)
{
    if (null !== $module && !is_string($module)) {
        require_once 'Zend/Navigation/Exception.php';
        throw new Zend_Navigation_Exception(
                'Invalid argument: $module must be a string or null');
    }

    $this->_module = $module;
    $this->_hrefCache = null;
    return $this;
}

/**
 * Returns module name to use when assembling URL
 *
 * @see getHref()
 *
 * @return string|null  module name or null
 */
public function getModule()
{
    return $this->_module;
}

/**
 * Sets params to use when assembling URL
 *
 * @see getHref()
 *
 * @param  array|null $params        [optional] page params. Default is null
 *                                   which sets no params.
 * @return Zend_Navigation_Page_Mvc  fluent interface, returns self
 */
public function setParams(array $params = null)
{
    if (null === $params) {
        $this->_params = array();
    } else {
        // TODO: do this more intelligently?
        $this->_params = $params;
    }

    $this->_hrefCache = null;
    return $this;
}

/**
 * Returns params to use when assembling URL
 *
 * @see getHref()
 *
 * @return array  page params
 */
public function getParams()
{
    return $this->_params;
}

/**
 * Sets route name to use when assembling URL
 *
 * @see getHref()
 *
 * @param  string $route              route name to use when assembling URL
 * @return Zend_Navigation_Page_Mvc   fluent interface, returns self
 * @throws Zend_Navigation_Exception  if invalid $route is given
 */
public function setRoute($route)
{
    if (null !== $route && (!is_string($route) || strlen($route) < 1)) {
        require_once 'Zend/Navigation/Exception.php';
        throw new Zend_Navigation_Exception(
             'Invalid argument: $route must be a non-empty string or null');
    }

    $this->_route = $route;
    $this->_hrefCache = null;
    return $this;
}

/**
 * Returns route name to use when assembling URL
 *
 * @see getHref()
 *
 * @return string  route name
 */
public function getRoute()
{
    return $this->_route;
}

/**
 * Sets whether params should be reset when assembling URL
 *
 * @see getHref()
 *
 * @param  bool $resetParams         whether params should be reset when
 *                                   assembling URL
 * @return Zend_Navigation_Page_Mvc  fluent interface, returns self
 */
public function setResetParams($resetParams)
{
    $this->_resetParams = (bool) $resetParams;
    $this->_hrefCache = null;
    return $this;
}

/**
 * Returns whether params should be reset when assembling URL
 *
 * @see getHref()
 *
 * @return bool  whether params should be reset when assembling URL
 */
public function getResetParams()
{
    return $this->_resetParams;
}

/**
 * Sets whether href should be encoded when assembling URL
 *
 * @see getHref()
 *
 * @param  bool $resetParams         whether href should be encoded when
 *                                   assembling URL
 * @return Zend_Navigation_Page_Mvc  fluent interface, returns self
 */
public function setEncodeUrl($encodeUrl)
{
    $this->_encodeUrl = (bool) $encodeUrl;
    $this->_hrefCache = null;
    return $this;
}

/**
 * Returns whether herf should be encoded when assembling URL
 *
 * @see getHref()
 *
 * @return bool whether herf should be encoded when assembling URL
 */
public function getEncodeUrl()
{
    return $this->_encodeUrl;
}

/**
 * Sets action helper for assembling URLs
 *
 * @see getHref()
 *
 * @param  Zend_Controller_Action_Helper_Url $uh  URL helper
 * @return void
 */
public static function setUrlHelper(Zend_Controller_Action_Helper_Url $uh)
{
    self::$_urlHelper = $uh;
}

// Public methods:

/**
 * Returns an array representation of the page
 *
 * @return array  associative array containing all page properties
 */
public function toArray()
{
    return array_merge(
        parent::toArray(),
        array(
            'action'       => $this->getAction(),
            'controller'   => $this->getController(),
            'module'       => $this->getModule(),
            'params'       => $this->getParams(),
            'route'        => $this->getRoute(),
            'reset_params' => $this->getResetParams()
        ));
}

}

Added code tags

Hi Ulrich, can you add a patch file for this and some tests? Thanks.

Ok, here is the patch file. I don't know how to attach a file here, so I just Post it..

--- Mvc_Orig.php 2010-01-06 03:05:09.000000000 +0100 +++ Mvc.php 2011-01-26 11:57:51.000000000 +0100 @@ -93,6 +93,14 @@ * @var bool */ protected $_resetParams = true; +
+ /** + * Whether href should be encoded when assembling URL + * + * @see getHref() + * @var bool + */ + protected $_encodeUrl = true;

 /**
  * Cached href

@@ -201,7 +209,9 @@

     $url = self::$_urlHelper->url($params,
                                   $this->getRoute(),

- $this->getResetParams()); + $this->getResetParams(), + $this->getEncodeUrl() + );

     return $this->_hrefCache = $url;
 }

@@ -403,6 +413,34 @@ { return $this->_resetParams; } +
+ /** + * Sets whether href should be encoded when assembling URL + * + * @see getHref() + * + * @param bool $resetParams whether href should be encoded when + * assembling URL + * @return Zend_Navigation_Page_Mvc fluent interface, returns self + */ + public function setEncodeUrl($encodeUrl) + { + $this->_encodeUrl = (bool) $encodeUrl; + $this->_hrefCache = null; + return $this; + } +
+ /** + * Returns whether herf should be encoded when assembling URL + * + * @see getHref() + * + * @return bool whether herf should be encoded when assembling URL + */ + public function getEncodeUrl() + { + return $this->_encodeUrl; + }

 /**
  * Sets action helper for assembling URLs

@@ -434,7 +472,8 @@ 'module' => $this->getModule(), 'params' => $this->getParams(), 'route' => $this->getRoute(), - 'reset_params' => $this->getResetParams() + 'reset_params' => $this->getResetParams(), + 'encodeUrl' => $this->getEncodeUrl(), )); } }

Please add code tags!

Sorry!


--- Mvc_Orig.php    2010-01-06 03:05:09.000000000 +0100
+++ Mvc.php 2011-01-26 11:57:51.000000000 +0100
@@ -93,6 +93,14 @@
      * @var bool
      */
     protected $_resetParams = true;
+          
+    /**
+     * Whether href should be encoded when assembling URL
+     *
+     * @see getHref()
+     * @var bool
+     */
+    protected $_encodeUrl = true;
 
     /**
      * Cached href
@@ -201,7 +209,9 @@
 
         $url = self::$_urlHelper->url($params,
                                       $this->getRoute(),
-                                      $this->getResetParams());
+                                      $this->getResetParams(),
+                                      $this->getEncodeUrl()
+                                      );
 
         return $this->_hrefCache = $url;
     }
@@ -403,6 +413,34 @@
     {
         return $this->_resetParams;
     }
+    
+    /**
+     * Sets whether href should be encoded when assembling URL
+     *
+     * @see getHref()
+     *
+     * @param  bool $resetParams         whether href should be encoded when
+     *                                   assembling URL
+     * @return Zend_Navigation_Page_Mvc  fluent interface, returns self
+     */
+    public function setEncodeUrl($encodeUrl)
+    {
+        $this->_encodeUrl = (bool) $encodeUrl;
+        $this->_hrefCache = null;
+        return $this;
+    }
+    
+    /**
+     * Returns whether herf should be encoded when assembling URL
+     *
+     * @see getHref()
+     *
+     * @return bool whether herf should be encoded when assembling URL
+     */
+    public function getEncodeUrl()
+    {
+        return $this->_encodeUrl;
+    }
 
     /**
      * Sets action helper for assembling URLs
@@ -434,7 +472,8 @@
                 'module'       => $this->getModule(),
                 'params'       => $this->getParams(),
                 'route'        => $this->getRoute(),
-                'reset_params' => $this->getResetParams()
+                'reset_params' => $this->getResetParams(),
+                'encodeUrl'    => $this->getEncodeUrl(),
             ));
     }
 }

Thanks for your help! I will write some test cases.

Unit tests

Extended unit test attached.

Fixed in r24444 and via ZF2 PR