Cakephp .json ext дает отсутствующий метод

У меня есть раскрывающийся список, в котором onChange я использую ajax для загрузки некоторого .json из метода в контроллере.

Однако я возвращаю error 404

Если я удалю расширение .json, я получу error 500 отсутствующий шаблон, который я тоже не смог разрешить. Я пробовал другое решение. В любом случае я бы предпочел использовать расширение .json и позволить cakephp вернуть правильный формат JSON.

Missing Method in StrategiesConditionsController
Cake\Controller\Exception\MissingActionException

Error The action conditions.json is not defined in StrategiesConditionsController

Create StrategiesConditionsController::conditions.json() in file: src/Controller/StrategiesConditionsController.php.

Прочитав документ пару раз, я уверен, что у меня правильные маршруты.

маршруты.php

<?php
/**
 * Routes configuration.
 *
 * In this file, you set up routes to your controllers and their actions.
 * Routes are very important mechanism that allows you to freely connect
 * different URLs to chosen controllers and their actions (functions).
 *
 * It's loaded within the context of `Application::routes()` method which
 * receives a `RouteBuilder` instance `$routes` as method argument.
 *
 * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
 * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
 *
 * Licensed under The MIT License
 * For full copyright and license information, please see the LICENSE.txt
 * Redistributions of files must retain the above copyright notice.
 *
 * @copyright     Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
 * @link          https://cakephp.org CakePHP(tm) Project
 * @license       https://opensource.org/licenses/mit-license.php MIT License
 */

use Cake\Http\Middleware\CsrfProtectionMiddleware;
use Cake\Routing\Route\DashedRoute;
use Cake\Routing\RouteBuilder;
use Cake\Routing\Router;

/*
 * The default class to use for all routes
 *
 * The following route classes are supplied with CakePHP and are appropriate
 * to set as the default:
 *
 * - Route
 * - InflectedRoute
 * - DashedRoute
 *
 * If no call is made to `Router::defaultRouteClass()`, the class used is
 * `Route` (`Cake\Routing\Route\Route`)
 *
 * Note that `Route` does not do any inflections on URLs which will result in
 * inconsistently cased URLs when used with `:plugin`, `:controller` and
 * `:action` markers.
 */
/** @var \Cake\Routing\RouteBuilder $routes */
$routes->setRouteClass(DashedRoute::class);

$routes->scope('/', function (RouteBuilder $routes) {
    $routes->setExtensions(['json']);
    $routes->resources('StrategiesConditions', [
        'map' => [
            'conditions' => [
                'action' => 'conditions',
                'method' => 'post'
            ]
        ],
        'only' => ['conditions']
     ]);
});

$routes->scope('/', function (RouteBuilder $builder) {
    // Register scoped middleware for in scopes.
    $builder->registerMiddleware('csrf', new CsrfProtectionMiddleware([
        'httpOnly' => true,
    ]));

    /*
     * Apply a middleware to the current route scope.
     * Requires middleware to be registered through `Application::routes()` with `registerMiddleware()`
     */
    $builder->applyMiddleware('csrf');

    /*
     * Here, we are connecting '/' (base path) to a controller called 'Pages',
     * its action called 'display', and we pass a param to select the view file
     * to use (in this case, templates/Pages/home.php)...
     */
    $builder->connect('/', ['controller' => 'Pages', 'action' => 'display', 'home']);

    /*
     * ...and connect the rest of 'Pages' controller's URLs.
     */
    $builder->connect('/pages/*', ['controller' => 'Pages', 'action' => 'display']);

    /*
     * Connect catchall routes for all controllers.
     *
     * The `fallbacks` method is a shortcut for
     *
     * ```
     * $builder->connect('/:controller', ['action' => 'index']);
     * $builder->connect('/:controller/:action/*', []);
     * ```
     *
     * You can remove these routes once you've connected the
     * routes you want in your application.
     */
    $builder->fallbacks();
});

Router::prefix('admin', function (RouteBuilder $routes) {
    $routes->connect('/', ['controller' => 'Users', 'action' => 'index']);
    $routes->fallbacks(DashedRoute::class);
});

/*
 * If you need a different set of middleware or none at all,
 * open new scope and define routes there.
 *
 * ```
 * $routes->scope('/api', function (RouteBuilder $builder) {
 *     // No $builder->applyMiddleware() here.
 *     // Connect API actions here.
 * });
 * ```
 */

стратегииУсловияКонтроллер

public function conditions()
{
    $this->request->allowMethod(['post']);

    if ($this->request->is('ajax')) {
        $this->response = $this->response->withDisabledCache();
    }

    $strategy_id = $this->request->getData('strategy_id');
    
    $strategiesConditions = $this->StrategiesConditions->find('all', [
        'where' => ['strategy_id' => $strategy_id],
    ]);
    $this->viewBuilder()->setOption('serialize', ['strategiesConditions']);
}

Консоль Cakephp имеет 8 маршрутов, показывающих

Route name  URI template    Defaults
pages:display   /   
{
    "controller": "Pages",
    "action": "display",
    "0": "home",
    "plugin": null
}
pages:display   /pages/*    
{
    "controller": "Pages",
    "action": "display",
    "plugin": null
}
_controller:index   /{controller}   
{
    "action": "index",
    "plugin": null
}
_controller:_action /{controller}/{action}/*    
{
    "plugin": null,
    "action": "index"
}
admin:users:index   /admin  
{
    "controller": "Users",
    "action": "index",
    "prefix": "Admin",
    "plugin": null
}
admin:_controller:index /admin/{controller} 
{
    "action": "index",
    "prefix": "Admin",
    "plugin": null
}
admin:_controller:_action   /admin/{controller}/{action}/*  
{
    "prefix": "Admin",
    "plugin": null,
    "action": "index"
}
strategiesconditions:conditions /strategies-conditions/conditions   
{
    "controller": "StrategiesConditions",
    "action": "conditions",
    "_method": "post",
    "plugin": null
}

Обновление на вкладке истории в наборе отладки

Request
Routing Params
controller StrategiesConditions
action conditions.json
pass (empty)
plugin (null)
_matchedRoute /{controller}/{action}/*
_ext (null)
Post data
strategy_id 11
Query string
No querystring data.

Cookie
csrfToken dd12f852560a384d39206e511f1857f77f71da2eadb023a6c67ae346
PHPSESSID 3d2jt7dgpo09af8b1908quljpn
Matched Route
template /{controller}/{action}/*

и вкладка маршрутов:

Routes
Toggle debugkit internal routes
Route name  URI template    Defaults
pages:display   /   
{
    "controller": "Pages",
    "action": "display",
    "0": "home",
    "plugin": null
}
pages:display   /pages/*    
{
    "controller": "Pages",
    "action": "display",
    "plugin": null
}
_controller:index   /{controller}   
{
    "action": "index",
    "plugin": null
}
_controller:_action /{controller}/{action}/*    
{
    "plugin": null,
    "action": "index"
}
admin:users:index   /admin  
{
    "controller": "Users",
    "action": "index",
    "prefix": "Admin",
    "plugin": null
}
admin:_controller:index /admin/{controller} 
{
    "action": "index",
    "prefix": "Admin",
    "plugin": null
}
admin:_controller:_action   /admin/{controller}/{action}/*  
{
    "prefix": "Admin",
    "plugin": null,
    "action": "index"
}
strategiesconditions:conditions /strategies-conditions/conditions   
{
    "controller": "StrategiesConditions",
    "action": "conditions",
    "_method": "post",
    "plugin": null
}

URL-адрес запроса

http://localhost:8888/trading-journal/strategies-conditions/conditions.json

Приложение.php

        // Add routing middleware.
        // If you have a large number of routes connected, turning on routes
        // caching in production could improve performance. For that when
        // creating the middleware instance specify the cache config name by
        // using it's second constructor argument:
        // `new RoutingMiddleware($this, '_cake_routes_')`
        ->add(new RoutingMiddleware($this))

person Keith Power    schedule 06.08.2020    source источник
comment
Наличие жадного маршрута, такого как /{controller}/{action}/*, перед другими маршрутами никогда не бывает хорошим. К сожалению, оболочка маршрутов не включает параметры маршрута, поэтому невозможно определить, какие расширения зарегистрированы для какого маршрута :( Так что, по сути, нам нужно будет увидеть ваш полный код маршрутов, и URL-адрес запроса также может быть полезен.   -  person ndm    schedule 06.08.2020
comment
Да, также, если вы используете комплект отладки (который вам следует ;)), вы можете проверить, какой шаблон маршрута соответствует на вкладке Запрос или, что еще лучше, на вкладке Маршруты , который содержит больше сведений о маршрутах и ​​выделяет соответствующий маршрут.   -  person ndm    schedule 06.08.2020
comment
Я обновил route.php, чтобы показать полный код. То, что я опубликовал, было комплектом отладки формы вывода на вкладке «Маршруты», который изменился, когда я обновил файлы маршрутов. Я не могу получить информацию о вкладке «Запрос» из вызова ajax, только с других страниц, которые, вероятно, бесполезны.   -  person Keith Power    schedule 06.08.2020
comment
Вы можете получить информацию о комплекте отладки для предыдущих/ajax-запросов, выбрав более ранний запрос в вкладка История! Глядя на маршруты, уже кажется, что жадный маршрут, о котором я упоминал, перехватывает ваши запросы, они созданы $this->fallbacks(). Пожалуйста, проверьте предыдущий запрос в наборе отладки, чтобы убедиться, что он /{controller}/{action}/* перехватывает запрос AJAX, а затем переместите область действия с ресурсами в начало ваших маршрутов (маршруты обрабатываются в порядке очереди).   -  person ndm    schedule 06.08.2020
comment
Отлично, не знал, что можно оглянуться на историю запросов и маршрутов. Ницца. я обновил код   -  person Keith Power    schedule 06.08.2020
comment
Как и предполагалось, совпавший маршрут — /{controller}/{action}/*. Поэтому, пожалуйста, попробуйте мое предложение и переместите свою область с ресурсами перед областью с запасными вариантами.   -  person ndm    schedule 06.08.2020
comment
Я обновил route.php и обновил код здесь, и, к сожалению, точно такой же, совпадающие маршруты все еще /{controller}/{action}/*   -  person Keith Power    schedule 06.08.2020
comment
Вы уверены, что сохранили файл маршрутов после его изменения? Также вы, возможно, используете кеширование маршрута (в вашем src/Application.php проверьте второй аргумент конструктора RoutingMiddleware)?   -  person ndm    schedule 06.08.2020
comment
да все сохранено. Я добавил код для Application.php, не уверен, что это правильно. Я уже несколько раз чистил кеш.   -  person Keith Power    schedule 06.08.2020
comment
Выглядит правильно, т.е. кэширование маршрута не активировано. На всякий случай под кешем я подразумеваю папку tmp/cache/! И маршруты в console/debugkit по-прежнему показывают /{controller}/{action}/* before /strategies-conditions/conditions? Можете ли вы попробовать удалить все остальное в файле маршрутов, кроме области маршрутов ресурсов?   -  person ndm    schedule 06.08.2020
comment
Давайте продолжим это обсуждение в чате.   -  person Keith Power    schedule 06.08.2020


Ответы (1)


'method' => 'POST' должен был быть в верхнем регистре. Это был не документ. Был сделан запрос на изменение, поэтому он не чувствителен к регистру.

$routes->scope('/', function (RouteBuilder $routes) {
    $routes->setExtensions(['json']);
    $routes->resources('StrategiesConditions', [
        'map' => [
            'conditions' => [
                'action' => 'conditions',
                'method' => 'POST'
            ]
        ],
        'only' => ['conditions']
     ]);
});
person Keith Power    schedule 25.08.2020