zf2 restful not reach update方法

时间:2013-02-07 10:22:07

标签: rest zend-framework2

我做了一个安静的控制器,如果我发送id,get方法会收到它。但是当我更新表单时,我希望更新方法可以处理,但是我无法找到正确的配置,在这个问题的1天之后我决定将它放在这里。

这里涉及的代码 模块配置中的路由:

        'activities' => array(
            'type' => 'segment',
            'options' => array(
                'route' => '/activities[/:id][/:action][.:formatter]',
                'defaults' => array(
                    'controller' => 'activities'
                ),
                'constraints' => array(
                    'formatter' => '[a-zA-Z0-9_-]*',
                    'id' => '[0-9_-]*'
                ),
            ),
        ),

管制员负责人:

namespace Clock\Controller;

use Zend\Mvc\Controller\AbstractRestfulController;
use Zend\Mvc\MvcEvent;
use Zend\View\Model\ViewModel;
use Zend\Form\Annotation\AnnotationBuilder;
use Zend\Form;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\EntityRepository;
use Clock\Entity\Activity;
use \Clock\Entity\Project;

Wich contains the get method:

    public function get($id)
    {
        $entity = $this->getRepository()->find($id);
        $form = $this->buildForm(new Activity());
        #$form->setAttribute('action', $this->url()->fromRoute("activities", array('action' => 'update')));
        $form->setAttribute('action', "/activities/$id/update");
        $form->bind($entity);
        return array(
            "activities" => $entity,
            "form" => $form
        );
    }

这提供了这个观点:

<h3>Edit activity</h3>
<div>
    <?php echo $this->form()->openTag($form);?>
    <?php echo $this->formSelect($form->get("project"));?><br>
    <?php echo $this->formInput($form->get("duration"));?><br>
    <?php echo $this->formInput($form->get("description"));?><br>
    <input type="submit" value="save changes" />
    <?php echo $this->form()->closeTag($form);?>
</div>

发送后,我希望活动中的更新方法能够控制,但我得到:

A 404 error occurred
Page not found.

The requested controller was unable to dispatch the request.

Controller:
    activities 

编辑:@DrBeza 这就是我得到的,我认为(不是路线中的主人)是对的:

Zend\Mvc\Router\Http\RouteMatch Object
(
    [length:protected] => 21
    [params:protected] => Array
        (
            [controller] => activities
            [id] => 30
            [action] => update
        )

    [matchedRouteName:protected] => activities
)

-

那就是它。 有什么帮助吗?

2 个答案:

答案 0 :(得分:3)

快速修复

RouteMatch对象尝试调度ActivitiesController::updateAction,但您已定义ActivitiesController::update 这是因为你使用了Restful Controller。 Controller::update - 方法专门与PUT - 请求相关联。您需要定义一个额外的方法来通过POST - 请求来处理更新。

我建议您定义ActivitiesController::updateAction,在docblock中明确说明它是为了处理POST更新请求并重构::updateAction::update以共享尽可能多的常见帮助方法可以快速解决。

公共URI结构信息

作为开始开发RESTful应用程序/ API时的一个很好的信息: ruby社区为您的资源建议以下url结构:

# These are restful 
/resource          GET (lists)   | POST (creates)
/resource/:id      PUT (updates) | DELETE (deletes)

# these are just helpers, not restful, and may accept POST too.
/resource/new      GET (shows the create-form), POST
/resource/:id/edit GET (shows the update-form), POST

详细问题分析

消费者将通过PUT发送详细更新,但发送HTML表单的浏览器只能发送GETPOST个请求。你永远不应该使用GET创建一些东西。因此,您必须在表单上下文中使用POST

从架构的角度来看问题,根据您的应用程序的大小,会出现多种可能性。

  • 对于小型应用程序,紧密集成(控制器中的形式处理和API处理)最适用。
  • 越来越大,您可能希望从Helper-Controllers(表单,网站处理)中拆分与API控制器通信的API控制器(仅限其他操作)
  • 要成为大型(众多API用户),您需要拥有专用的API服务器和专用的网站服务器(独立的应用程序!)。在这种情况下,您的网站将使用API​​服务器端(这就是Twitter正在做的事情)。 API服务器和网站服务器仍然可以共享库(用于过滤,实用程序)。

代码示例

作为一个教育范例,我原则上提出了an gist to show how such a controller could look like。该控制器是a)未经测试的b)未生产就绪且c)仅可轻微配置。

为了您的特殊兴趣,这里有两个关于更新的摘录:

/* the restful method, defined in AbstractRestfulController */
public function update($id, $data)
{
    $response = $this->getResponse();

    if ( ! $this->getService()->has($id) )
    {
        return $this->notFoundAction();
    }

    $form = $this->getEditForm();
    $form->setData($data);

    if ( ! $form->isValid() )
    {
        $response->setStatusCode(self::FORM_INVALID_STATUSCODE);
        return [ 'errors' => $form->getMessages() ];
    }

    $data = $form->getData(); // you want the filtered & validated data from the form, not the raw data from the request.

    $status = $this->getService()->update($id, $data);

    if ( ! $status )
    {
        $response->setStatusCode(self::SERVERSIDE_ERROR_STATUSCODE);
        return [ 'errors' => [self::SERVERSIDE_ERROR_MESSAGE] ];
    }

    // if everything went smooth, we just return the new representation of the entity.

    return $this->get($id);
}

以及满足浏览器请求的editAction

public function editAction()
{
    /*
     * basically the same as the newAction
     * differences:
     *  - first fetch the data from the service
     *  - prepopulate the form
     */

    $id = $this->params('id', false);
    $dataExists = $this->getService()->has($id);

    if ( ! $dataExists )
    {
        $this->flashMessenger()->addErrorMessage("No entity with {$id} is known");
        return $this->notFoundAction();
    }

    $request = $this->getRequest();
    $form = $this->getEditForm();
    $data = $this->getService()->get($id);

    if ( ! $request->isPost() )
    {
        $form->populateValues($data);
        return ['form' => $form];
    }

    $this->update($id, $request->getPost()->toArray());
    $response = $this->getResponse();

    if ( ! $response->isSuccess() )
    {
        return [ 'form' => $form ];
    }

    $this->flashMessenger()->addSuccessMessage('Entity changed successfully');
    return $this->redirect()->toRoute($this->routeIdentifiers['entity-changed']);
}

答案 1 :(得分:1)

该错误消息表明调度进程无法找到请求的控制器操作,因此使用notFoundAction()

我会检查匹配的路线,并确保值符合预期。您可以通过在模块的onBootstrap()方法中添加以下内容来完成此操作:

$e->getApplication()->getEventManager()->attach('route', function($event) {
    var_dump($event->getRouteMatch());
    exit;
});