2

IDを送信すると、getメソッドがそれを受信するRESTfulコントローラーを作成しました。しかし、フォームを更新すると、更新メソッドが処理されることを期待しますが、これに適切な構成を取得できず、この問題が発生した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
)

-

それでおしまい。何か助けはありますか?

4

2 に答える 2

3

クイックフィックス

RouteMatchオブジェクトはディスパッチを試みActivitiesController::updateActionますが、RestfulControllerを使用しているために定義ActivitiesController::update しました。Controller::update-Methodは、特に-Requestsに関連付けられてPUTいます。POST-Requestsを介して更新を処理するための追加のメソッドを定義する必要があります。

定義ActivitiesController::updateActionし、docblockで、POST-Updateリクエストを処理し、両方をリファクタリング::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フォームを送信するブラウザーは、送信GETまたはPOST要求のみを行うことができます。GET何かを作成するために使用しないでください。したがってPOST、forms-contextで使用する必要があります。

アーキテクチャの観点から問題を見ると、アプリケーションの大きさに応じて、さまざまな可能性が浮かび上がります。

  • 小さなアプリケーションの場合、緊密な統合(コントローラーでのフォーム処理とAPI処理)が最適です。
  • 大きくなると、APIコントローラー(フォーム、Webサイト処理)からAPIコントローラー(安らかなアクションのみ)を分割して、APIコントローラーと通信することができます。
  • 大きい(多数のAPIユーザー)場合は、専用のAPIサーバーと専用のWebサイトサーバー(独立したアプリケーション!)が必要になります。この場合、あなたのウェブサイトはAPIサーバーサイドを消費します(それがTwitterが行っていることです)。APIサーバーとWebサイトサーバーは引き続きライブラリを共有する場合があります(フィルタリング、ユーティリティ用)。

コードサンプル

教育的な例として、私はそのようなコントローラーが原理的にどのように見えるかを示すために要点を作成しました。このコントローラーは、a)テストされていないb)実稼働に対応しておらず、c)わずかに構成可能です。

ここでの特別な関心のために、更新に関する2つの抜粋を示します。

/* 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']);
}
于 2013-02-22T11:22:13.867 に答える
1

このエラーメッセージは、ディスパッチプロセスが要求されたコントローラアクションを見つけることができないため、を使用していることを示していnotFoundAction()ます。

一致するルートをチェックし、値が期待どおりであることを確認します。onBootstrap()これを行うには、モジュールのメソッドに以下を追加します。

$e->getApplication()->getEventManager()->attach('route', function($event) {
    var_dump($event->getRouteMatch());
    exit;
});
于 2013-02-07T16:34:53.780 に答える