zf2 restful не достигает метода обновления

Я сделал спокойный контроллер, что если я отправлю идентификатор, метод 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
        );
    }

Это соответствует этому мнению:

Edit activity

<div> <?php echo $this->form()->openTag($form);?> <?php echo $this->formSelect($form->get("project"));?>
<?php echo $this->formInput($form->get("duration"));?>
<?php echo $this->formInput($form->get("description"));?>
<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 

EDIT: @DrBeza Это то, что я получаю, что я думаю (не хозяин в маршрутах) прав:

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

    [matchedRouteName:protected] => activities
)

-

Вот и все. Любая помощь?

2
nl ja de

2 ответы

Быстрая починка

Объект RouteMatch пытается отправить ActivitiesController :: updateAction , но вы определили ActivitiesController :: update Это связано с использованием Restful Controller. Controller :: update -Method специально привязан к PUT -Requests. Вам необходимо определить дополнительный метод для обработки обновлений с помощью POST -Requests.

Я предлагаю вам определить ActivitiesController :: updateAction , очистить в docblock, он предназначен для обработки запросов POST-обновления и рефакторинг как :: updateAction , так и :: update , чтобы использовать как можно больше общих вспомогательных методов для быстрого решения.

Общая информация URI Structur

Как хорошая информация, когда вы начинаете разработку RESTful приложений/API: Сообщество рубинов предлагает следующую структуру 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 в контексте форм.

Рассматривая проблему с точки зрения архитектуры, появляется множество возможностей, в зависимости от того, насколько велика ваша заявка.

  • Для небольшого приложения наиболее эффективны тесная интеграция (обработка формы и обработка API в контроллере).
  • Приобретая больше, вы можете разделить API-контроллеры (только успокоительные действия) от Helper-Controllers (форма, обработка веб-сайта), которые говорят с вашими API-контроллерами.
  • Будучи большим (множество пользователей API), вы захотите иметь выделенные серверы API и выделенные серверы веб-сайтов (независимые приложения!). В этом случае ваш сайт будет использовать API-серверы (это то, что делает твиттер). Серверы API и серверы веб-сайтов по-прежнему могут совместно использовать библиотеки (для фильтрации, утилит).

Образец кода

В качестве примера обучения я сделал суть, чтобы показать, как такой контроллер может выглядеть как в принципе. Этот контроллер: 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']);
}
3
добавлено
Я честно не знаю: D Спасибо за признательность!
добавлено автор Samuel Herzog, источник
Как у этого нет больше голосов? Это было замечательно.
добавлено автор four43, источник
ey, спасибо за этот ответ и время, которое вы положили :)
добавлено автор user968865, источник

Это сообщение об ошибке указывает, что процесс отправки не может найти требуемое действие контроллера и, следовательно, использовать notFoundAction() .

Я бы проверял соответствие маршрута и следил за тем, чтобы значения были такими, как ожидалось. Вы можете сделать это, добавив следующее в свой метод onBootstrap() вашего модуля:

$e->getApplication()->getEventManager()->attach('route', function($event) {
    var_dump($event->getRouteMatch());
    exit;
});
1
добавлено
Я предполагаю, что действие называется updateAction, и оно общедоступно. Я также отменил бы действие на простое эхо. Как только это сработает, я медленно вернусь к существующим функциям и надеюсь, что это подчеркнет, где проблема.
добавлено автор DrBeza, источник
я редактировал вопрос с дампом
добавлено автор user968865, источник