Use URL segments as action method parameters in Zend Framework

时间:2022-11-24 11:12:38

In Kohana/CodeIgniter, I can have a URL in this form:

在Kohana / CodeIgniter中,我可以使用以下格式的URL:

http://www.name.tld/controller_name/method_name/parameter_1/parameter_2/parameter_3 ...

And then read the parameters in my controller as follows:

然后按如下方式读取控制器中的参数:

class MyController 
{
    public function method_name($param_A, $param_B, $param_C ...)
    {
        // ... code
    }
}

How do you achieve this in the Zend Framework?

你如何在Zend框架中实现这一目标?

5 个解决方案

#1


6  

Update (04/13/2016): The link in my answer below moved and has been fixed. However, just in case it disappears again -- here are a few alternatives that provide some in depth information on this technique, as well as use the original article as reference material:

更新(2016年4月13日):我的答案中的链接已移动并已修复。但是,如果它再次消失 - 这里有一些替代方案,提供有关此技术的一些深入信息,以及使用原始文章作为参考材料:


@Andrew Taylor's response is the proper Zend Framework way of handling URL parameters. However, if you would like to have the URL parameters in your controller's action (as in your example) - check out this tutorial on Zend DevZone.

@Andrew Taylor的回应是正确的Zend Framework处理URL参数的方式。但是,如果您想在控制器的操作中使用URL参数(如您的示例所示) - 请查看Zend DevZone上的本教程。

#2


11  

Take a look at the Zend_Controller_Router classes:

看一下Zend_Controller_Router类:

http://framework.zend.com/manual/en/zend.controller.router.html

These will allow you to define a Zend_Controller_Router_Route which maps to your URL in the way that you need.

这些将允许您定义Zend_Controller_Router_Route,它以您需要的方式映射到您的URL。

An example of having 4 static params for the Index action of the Index controller is:

为Index控制器的Index操作设置4个静态参数的示例是:

$router = new Zend_Controller_Router_Rewrite();

$router->addRoute(
    'index',
    new Zend_Controller_Router_Route('index/index/:param1/:param2/:param3/:param4', array('controller' => 'index', 'action' => 'index'))
);

$frontController->setRouter($router);

This is added to your bootstrap after you've defined your front controller.

在定义前端控制器后,会将其添加到引导程序中。

Once in your action, you can then use:

一旦进入您的行动,您就可以使用:

$this->_request->getParam('param1');

Inside your action method to access the values.

在您的操作方法中访问值。

Andrew

#3


4  

I have extended Zend_Controller_Action with my controller class and made the following changes:

我已经使用我的控制器类扩展了Zend_Controller_Action并进行了以下更改:

In dispatch($action) method replaced

在dispatch($ action)方法中替换

$this->$action();

with

call_user_func_array(array($this,$action), $this->getUrlParametersByPosition());

And added the following method

并添加了以下方法

/**
 * Returns array of url parts after controller and action
 */
protected function getUrlParametersByPosition()
{
    $request = $this->getRequest();
    $path = $request->getPathInfo();
    $path = explode('/', trim($path, '/'));
    if(@$path[0]== $request->getControllerName())
    {
        unset($path[0]);
    }
    if(@$path[1] == $request->getActionName())
    {
        unset($path[1]);
    }
    return $path;
}

Now for a URL like /mycontroller/myaction/123/321

现在为/ mycontroller / myaction / 123/321这样的URL

in my action I will get all the params following controller and action

在我的行动中,我将按照控制器和动作获得所有参数

public function editAction($param1 = null, $param2 = null)
{
    // $param1 = 123
    // $param2 = 321
}

Extra parameters in URL won't cause any error as you can send more params to method then defined. You can get all of them by func_get_args() And you can still use getParam() in a usual way. Your URL may not contain action name using default one.

URL中的额外参数不会导致任何错误,因为您可以向定义的方法发送更多参数。您可以通过func_get_args()获取所有这些并且您仍然可以以通常的方式使用getParam()。您的URL可能不包含使用默认名称的操作名称。

Actually my URL does not contain parameter names. Only their values. (Exactly as it was in the question) And you have to define routes to specify parameters positions in URL to follow the concepts of framework and to be able to build URLs using Zend methods. But if you always know the position of your parameter in URL you can easily get it like this.

实际上我的URL不包含参数名称。只有他们的价值观(正如在问题中一样)并且您必须定义路由以在URL中指定参数位置以遵循框架的概念并且能够使用Zend方法构建URL。但是,如果你总是知道你的参数在URL中的位置,你可以很容易地得到它。

That is not as sophisticated as using reflection methods but I guess provides less overhead.

这不像使用反射方法那么复杂,但我想提供更少的开销。

Dispatch method now looks like this:

Dispatch方法现在看起来像这样:

/**
 * Dispatch the requested action
 *
 * @param string $action Method name of action
 * @return void
 */
public function dispatch($action)
{
    // Notify helpers of action preDispatch state
    $this->_helper->notifyPreDispatch();

    $this->preDispatch();
    if ($this->getRequest()->isDispatched()) {
        if (null === $this->_classMethods) {
            $this->_classMethods = get_class_methods($this);
        }

        // preDispatch() didn't change the action, so we can continue
        if ($this->getInvokeArg('useCaseSensitiveActions') || in_array($action, $this->_classMethods)) {
            if ($this->getInvokeArg('useCaseSensitiveActions')) {
                trigger_error('Using case sensitive actions without word separators is deprecated; please do not rely on this "feature"');
            }
            //$this->$action();
            call_user_func_array(array($this,$action), $this->getUrlParametersByPosition()); 
        } else {
            $this->__call($action, array());
        }
        $this->postDispatch();
    }

    // whats actually important here is that this action controller is
    // shutting down, regardless of dispatching; notify the helpers of this
    // state
    $this->_helper->notifyPostDispatch();
}    

#4


3  

For a simpler method that allows for more complex configurations, try this post. In summary:

对于允许更复杂配置的更简单方法,请尝试这篇文章。综上所述:

Create application/configs/routes.ini

routes.popular.route = popular/:type/:page/:sortOrder
routes.popular.defaults.controller = popular
routes.popular.defaults.action = index
routes.popular.defaults.type = images
routes.popular.defaults.sortOrder = alltime
routes.popular.defaults.page = 1
routes.popular.reqs.type = \w+
routes.popular.reqs.page = \d+
routes.popular.reqs.sortOrder = \w+

Add to bootstrap.php

添加到bootstrap.php

// create $frontController if not already initialised
$frontController = Zend_Controller_Front::getInstance(); 

$config = new Zend_Config_Ini(APPLICATION_PATH . ‘/config/routes.ini’);
$router = $frontController->getRouter();
$router->addConfig($config,‘routes’);

#5


1  

Originally posted here http://cslai.coolsilon.com/2009/03/28/extending-zend-framework/

最初发布在这里http://cslai.coolsilon.com/2009/03/28/extending-zend-framework/

My current solution is as follows:

我目前的解决方案如下:

abstract class Coolsilon_Controller_Base 
    extends Zend_Controller_Action { 

    public function dispatch($actionName) { 
        $parameters = array(); 

        foreach($this->_parametersMeta($actionName) as $paramMeta) { 
            $parameters = array_merge( 
                $parameters, 
                $this->_parameter($paramMeta, $this->_getAllParams()) 
            ); 
        } 

        call_user_func_array(array(&$this, $actionName), $parameters); 
    } 

    private function _actionReference($className, $actionName) { 
        return new ReflectionMethod( 
            $className, $actionName 
        ); 
    } 

    private function _classReference() { 
        return new ReflectionObject($this); 
    } 

    private function _constructParameter($paramMeta, $parameters) { 
        return array_key_exists($paramMeta->getName(), $parameters) ? 
            array($paramMeta->getName() => $parameters[$paramMeta->getName()]) : 
            array($paramMeta->getName() => $paramMeta->getDefaultValue()); 
    } 

    private function _parameter($paramMeta, $parameters) { 
        return $this->_parameterIsValid($paramMeta, $parameters) ? 
            $this->_constructParameter($paramMeta, $parameters) : 
            $this->_throwParameterNotFoundException($paramMeta, $parameters); 
    } 

    private function _parameterIsValid($paramMeta, $parameters) { 
        return $paramMeta->isOptional() === FALSE 
            && empty($parameters[$paramMeta->getName()]) === FALSE; 
    } 

    private function _parametersMeta($actionName) { 
        return $this->_actionReference( 
                $this->_classReference()->getName(), 
                $actionName 
            ) 
            ->getParameters(); 
    } 

    private function _throwParameterNotFoundException($paramMeta, $parameters) { 
        throw new Exception(”Parameter: {$paramMeta->getName()} Cannot be empty”); 
    } 
} 

#1


6  

Update (04/13/2016): The link in my answer below moved and has been fixed. However, just in case it disappears again -- here are a few alternatives that provide some in depth information on this technique, as well as use the original article as reference material:

更新(2016年4月13日):我的答案中的链接已移动并已修复。但是,如果它再次消失 - 这里有一些替代方案,提供有关此技术的一些深入信息,以及使用原始文章作为参考材料:


@Andrew Taylor's response is the proper Zend Framework way of handling URL parameters. However, if you would like to have the URL parameters in your controller's action (as in your example) - check out this tutorial on Zend DevZone.

@Andrew Taylor的回应是正确的Zend Framework处理URL参数的方式。但是,如果您想在控制器的操作中使用URL参数(如您的示例所示) - 请查看Zend DevZone上的本教程。

#2


11  

Take a look at the Zend_Controller_Router classes:

看一下Zend_Controller_Router类:

http://framework.zend.com/manual/en/zend.controller.router.html

These will allow you to define a Zend_Controller_Router_Route which maps to your URL in the way that you need.

这些将允许您定义Zend_Controller_Router_Route,它以您需要的方式映射到您的URL。

An example of having 4 static params for the Index action of the Index controller is:

为Index控制器的Index操作设置4个静态参数的示例是:

$router = new Zend_Controller_Router_Rewrite();

$router->addRoute(
    'index',
    new Zend_Controller_Router_Route('index/index/:param1/:param2/:param3/:param4', array('controller' => 'index', 'action' => 'index'))
);

$frontController->setRouter($router);

This is added to your bootstrap after you've defined your front controller.

在定义前端控制器后,会将其添加到引导程序中。

Once in your action, you can then use:

一旦进入您的行动,您就可以使用:

$this->_request->getParam('param1');

Inside your action method to access the values.

在您的操作方法中访问值。

Andrew

#3


4  

I have extended Zend_Controller_Action with my controller class and made the following changes:

我已经使用我的控制器类扩展了Zend_Controller_Action并进行了以下更改:

In dispatch($action) method replaced

在dispatch($ action)方法中替换

$this->$action();

with

call_user_func_array(array($this,$action), $this->getUrlParametersByPosition());

And added the following method

并添加了以下方法

/**
 * Returns array of url parts after controller and action
 */
protected function getUrlParametersByPosition()
{
    $request = $this->getRequest();
    $path = $request->getPathInfo();
    $path = explode('/', trim($path, '/'));
    if(@$path[0]== $request->getControllerName())
    {
        unset($path[0]);
    }
    if(@$path[1] == $request->getActionName())
    {
        unset($path[1]);
    }
    return $path;
}

Now for a URL like /mycontroller/myaction/123/321

现在为/ mycontroller / myaction / 123/321这样的URL

in my action I will get all the params following controller and action

在我的行动中,我将按照控制器和动作获得所有参数

public function editAction($param1 = null, $param2 = null)
{
    // $param1 = 123
    // $param2 = 321
}

Extra parameters in URL won't cause any error as you can send more params to method then defined. You can get all of them by func_get_args() And you can still use getParam() in a usual way. Your URL may not contain action name using default one.

URL中的额外参数不会导致任何错误,因为您可以向定义的方法发送更多参数。您可以通过func_get_args()获取所有这些并且您仍然可以以通常的方式使用getParam()。您的URL可能不包含使用默认名称的操作名称。

Actually my URL does not contain parameter names. Only their values. (Exactly as it was in the question) And you have to define routes to specify parameters positions in URL to follow the concepts of framework and to be able to build URLs using Zend methods. But if you always know the position of your parameter in URL you can easily get it like this.

实际上我的URL不包含参数名称。只有他们的价值观(正如在问题中一样)并且您必须定义路由以在URL中指定参数位置以遵循框架的概念并且能够使用Zend方法构建URL。但是,如果你总是知道你的参数在URL中的位置,你可以很容易地得到它。

That is not as sophisticated as using reflection methods but I guess provides less overhead.

这不像使用反射方法那么复杂,但我想提供更少的开销。

Dispatch method now looks like this:

Dispatch方法现在看起来像这样:

/**
 * Dispatch the requested action
 *
 * @param string $action Method name of action
 * @return void
 */
public function dispatch($action)
{
    // Notify helpers of action preDispatch state
    $this->_helper->notifyPreDispatch();

    $this->preDispatch();
    if ($this->getRequest()->isDispatched()) {
        if (null === $this->_classMethods) {
            $this->_classMethods = get_class_methods($this);
        }

        // preDispatch() didn't change the action, so we can continue
        if ($this->getInvokeArg('useCaseSensitiveActions') || in_array($action, $this->_classMethods)) {
            if ($this->getInvokeArg('useCaseSensitiveActions')) {
                trigger_error('Using case sensitive actions without word separators is deprecated; please do not rely on this "feature"');
            }
            //$this->$action();
            call_user_func_array(array($this,$action), $this->getUrlParametersByPosition()); 
        } else {
            $this->__call($action, array());
        }
        $this->postDispatch();
    }

    // whats actually important here is that this action controller is
    // shutting down, regardless of dispatching; notify the helpers of this
    // state
    $this->_helper->notifyPostDispatch();
}    

#4


3  

For a simpler method that allows for more complex configurations, try this post. In summary:

对于允许更复杂配置的更简单方法,请尝试这篇文章。综上所述:

Create application/configs/routes.ini

routes.popular.route = popular/:type/:page/:sortOrder
routes.popular.defaults.controller = popular
routes.popular.defaults.action = index
routes.popular.defaults.type = images
routes.popular.defaults.sortOrder = alltime
routes.popular.defaults.page = 1
routes.popular.reqs.type = \w+
routes.popular.reqs.page = \d+
routes.popular.reqs.sortOrder = \w+

Add to bootstrap.php

添加到bootstrap.php

// create $frontController if not already initialised
$frontController = Zend_Controller_Front::getInstance(); 

$config = new Zend_Config_Ini(APPLICATION_PATH . ‘/config/routes.ini’);
$router = $frontController->getRouter();
$router->addConfig($config,‘routes’);

#5


1  

Originally posted here http://cslai.coolsilon.com/2009/03/28/extending-zend-framework/

最初发布在这里http://cslai.coolsilon.com/2009/03/28/extending-zend-framework/

My current solution is as follows:

我目前的解决方案如下:

abstract class Coolsilon_Controller_Base 
    extends Zend_Controller_Action { 

    public function dispatch($actionName) { 
        $parameters = array(); 

        foreach($this->_parametersMeta($actionName) as $paramMeta) { 
            $parameters = array_merge( 
                $parameters, 
                $this->_parameter($paramMeta, $this->_getAllParams()) 
            ); 
        } 

        call_user_func_array(array(&$this, $actionName), $parameters); 
    } 

    private function _actionReference($className, $actionName) { 
        return new ReflectionMethod( 
            $className, $actionName 
        ); 
    } 

    private function _classReference() { 
        return new ReflectionObject($this); 
    } 

    private function _constructParameter($paramMeta, $parameters) { 
        return array_key_exists($paramMeta->getName(), $parameters) ? 
            array($paramMeta->getName() => $parameters[$paramMeta->getName()]) : 
            array($paramMeta->getName() => $paramMeta->getDefaultValue()); 
    } 

    private function _parameter($paramMeta, $parameters) { 
        return $this->_parameterIsValid($paramMeta, $parameters) ? 
            $this->_constructParameter($paramMeta, $parameters) : 
            $this->_throwParameterNotFoundException($paramMeta, $parameters); 
    } 

    private function _parameterIsValid($paramMeta, $parameters) { 
        return $paramMeta->isOptional() === FALSE 
            && empty($parameters[$paramMeta->getName()]) === FALSE; 
    } 

    private function _parametersMeta($actionName) { 
        return $this->_actionReference( 
                $this->_classReference()->getName(), 
                $actionName 
            ) 
            ->getParameters(); 
    } 

    private function _throwParameterNotFoundException($paramMeta, $parameters) { 
        throw new Exception(”Parameter: {$paramMeta->getName()} Cannot be empty”); 
    } 
}