handleRequest() 在同一请求中调用两次,$Action 不同

handleRequest() called twice in same request, $Action is different

我有一条自定义路线:

/create//$Action/$ID

有一个动作:

public function Edit(SS_HTTPRequest $request) {
    $id = $this->getRequest()->params()['ID'];
    if($this->request->isPost()) return UploadForm::create($this, 'Edit/' . $id, 'SubmitImportedModule');;
    return $this->renderWith(array("Edit", "Page"));
}

和自定义表单:

class UploadForm extends Form {
    public function __construct($controller, $name, $action) {
        $fields = FieldList::create(
            TextField::create('Title', 'Title'),
            $course = UploadField::create('Upload', 'Upload')
        );

        $actions = FieldList::create(
            FormAction::create($action, 'Add Resource')
        );
        $validator = RequiredFields::create('Name');

        parent::__construct($controller, $name, $fields, $actions, $validator);
    }
}

如果路径是 /create/Edit/ 上传字段工作正常。但是,如果路径是 /create/Edit/1/ 服务器响应:

Action '1' isn't available on class UploadImportedCourseForm.

深入研究 RequestHandler 中的 handleRequest 我发现它被调用了两次,每次都到达第 180 行,它查看对象 latestParam()。第一次叫Action是Edit,意料之中,第二次叫1,其实就是ID。

同一个请求中的操作有何变化?我该如何着手解决我的问题?我认为我可以解决此问题的唯一方法是改为使用 ID 隐藏字段。

一般来说,创建表单的方法不应该过于复杂。他们只需要 return 一个表格。关于动态 ID,您可以通过几种不同的方式执行此操作——您可以通过隐藏字段传递 ID 并创建一个类似 getIDFromRequest() 的方法来检查 URL 和请求正文。

private static $allowed_actions = ['EditForm'];

public function EditForm() {
    return UploadForm::create($this, __FUNCTION__, 'yourAction');
}

class UploadForm extends Form {
    protected function getIDFromRequest(SS_HTTPRequest $r)
    {
        return $r->param('ID') ?: $r->postVar('ID');
    }

    public function __construct($controller, $name, $action) {
        $fields = FieldList::create(
            TextField::create('Title', 'Title'),
            HiddenField::create('ID','', $this->getIDFromRequest($controller->getRequest())),
            $course = UploadField::create('Upload', 'Upload')
        );

        $actions = FieldList::create(
            FormAction::create($action, 'Add Resource')
        );
        $validator = RequiredFields::create('Name');

        parent::__construct($controller, $name, $fields, $actions, $validator);
    }
}

或者,根据我可以推断出您正在尝试做的事情,我认为子控制器在这里更有意义。创建一个单独的请求处理程序,即 ID-aware。如果您要执行大量此类操作,这将使您的扩展更加清晰。

private static $url_handlers [
    'yourpath/$ID' => 'handleEditForm'
];
private static $allowed_actions = ['handleEditForm'];

public function handleEditForm(SS_HTTPRequest $r)
{
    $obj = SomeObject::get()->byID($r->param('ID')) {
        if(!$obj) $this->httpError(404);
    }

    $handler = new MyController_EditRequest($this, $obj);
    return $handler->handleRequest($r, DataModel::inst());
}

class MyController_EditRequest extends RequestHandler
{
    protected $parent;

    protected $obj;

    private static $allowed_actions = ['edit', 'EditForm'];

    public function __construct(MyController $controller, SomeDataObject, $obj)
    {
        $this->parent = $controller;
        $this->obj = $obj;

        parent::__construct();
    }

    public function edit(SS_HTTPRequest $r) 
    {
        return $this->renderWith(['SomeTemplate_edit','Page']);
    }

    public function Link()
    {
        return $this->parent->Link('yourpath/'.$this->obj->ID);
    }

    public function EditForm()
    {
        return UploadForm::create($this, __FUNCTION__, 'yourAction', $obj->ID)
    }
}

class UploadForm extends Form {

    public function __construct($controller, $name, $action, $id) {
        $fields = FieldList::create(
            TextField::create('Title', 'Title'),
            HiddenField::create('ID','', $id),
            $course = UploadField::create('Upload', 'Upload')
        );

        $actions = FieldList::create(
            FormAction::create($action, 'Add Resource')
        );
        $validator = RequiredFields::create('Name');

        parent::__construct($controller, $name, $fields, $actions, $validator);
    }
}

您的子控制器是 DataObject-aware,因此永远不会混淆事物的来源。您已经从中提取了 post vars 和 URLs 的抽象。