Добавить новые методы в контроллер ресурсов в Laravel

141

Я хочу знать, можно ли добавлять новые методы к контроллеру ресурсов в Laravel и как вы это делаете.

Я знаю, что эти методы используются по умолчанию (индексировать, создавать, сохранять, редактировать, обновлять, уничтожать). Теперь я хочу добавить к тому же контроллеру дополнительные методы и маршруты.

Это возможно?

user2403824
источник

Ответы:

267

Просто добавьте маршрут к этому методу отдельно, прежде чем регистрировать ресурс:

Route::get('foo/bar', 'FooController@bar');
Route::resource('foo', 'FooController');
Джозеф Зильбер
источник
7
Обратите внимание , что ваши новые методы должны идти выше::resource в противном случае вы получите сообщение об ошибке «Нет результаты запроса для модели».
mpen
Как передать такой параметр, как {id}? В настоящее время я закодировал свой собственный метод в файле routes.php (например, здесь laravel.com/docs/5.1/routing#route-parameters ). В идеале я бы хотел передать параметр для запуска в FooController.
ATutorMe 08
1
Обнаружил проблему - не было в синтаксисе Route. На самом деле был в каком-то настраиваемом промежуточном программном обеспечении, которое я использую! Route :: get ('foo / {id} / bar', 'FooController @ bar'); передаст идентификатор в метод bar ($ id). Благодарность!
ATutorMe 08
Может кто-нибудь объяснить, почему настраиваемый маршрут должен идти выше маршрута ресурса ??? Я провел несколько тестов и, кажется, не
вижу разницы
3
@RicardoVigatti - Ресурс регистрирует этот маршрут: Route::get('foo/{id}', ...). Это поглощает все маршруты, начинающиеся с fooи имеющие один дополнительный сегмент, включая foo/bar.
Joseph Silber
32

Я просто сделал это, чтобы добавить метод «удаления» GET.

После создания файлов вам просто нужно добавить

'AntonioRibeiro\Routing\ExtendedRouterServiceProvider',

к 'провайдерам' в вашем приложении / config.php

Отредактируйте псевдоним Route в этом же файле:

'Route'           => 'Illuminate\Support\Facades\Route',

меняя это на

'Route'           => 'AntonioRibeiro\Facades\ExtendedRouteFacade',

И убедитесь, что эти файлы загружаются автоматически, они должны находиться в каком-то каталоге, который есть у вас в composer.json (раздел «автозагрузка»).

Тогда вам просто необходимо:

Route::resource('users', 'UsersController');

И это (посмотрите на последнюю строку) результат, если вы запустите php artisan routes:

список маршрутов Это мои исходные файлы:

ExtendedRouteFacade.pas

<?php namespace AntonioRibeiro\Facades;

use Illuminate\Support\Facades\Facade as IlluminateFacade;

class ExtendedRouteFacade extends IlluminateFacade {

    /**
     * Determine if the current route matches a given name.
     *
     * @param  string  $name
     * @return bool
     */
    public static function is($name)
    {
        return static::$app['router']->currentRouteNamed($name);
    }

    /**
     * Determine if the current route uses a given controller action.
     *
     * @param  string  $action
     * @return bool
     */
    public static function uses($action)
    {
        return static::$app['router']->currentRouteUses($action);
    }

    /**
     * Get the registered name of the component.
     *
     * @return string
     */
    protected static function getFacadeAccessor() { return 'router'; }

}

ExtendedRouter.pas

<?php namespace AntonioRibeiro\Routing;

class ExtendedRouter extends \Illuminate\Routing\Router {

    protected $resourceDefaults = array('index', 'create', 'store', 'show', 'edit', 'update', 'destroy', 'delete');

    /**
     * Add the show method for a resourceful route.
     *
     * @param  string  $name
     * @param  string  $base
     * @param  string  $controller
     * @return void
     */
    protected function addResourceDelete($name, $base, $controller)
    {
        $uri = $this->getResourceUri($name).'/{'.$base.'}/destroy';

        return $this->get($uri, $this->getResourceAction($name, $controller, 'delete'));
    }

}

ExtendedRouteServiceProvider.pas

<?php namespace AntonioRibeiro\Routing;

use Illuminate\Support\ServiceProvider;

class ExtendedRouterServiceProvider extends ServiceProvider {

    /**
     * Indicates if loading of the provider is deferred.
     *
     * @var bool
     */
    protected $defer = true;

    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        $this->app['router'] = $this->app->share(function() { return new ExtendedRouter($this->app); });
    }

    /**
     * Get the services provided by the provider.
     *
     * @return array
     */
    public function provides()
    {
        return array('router');
    }

}
Антонио Карлос Рибейро
источник
3
Не могли бы вы предоставить то же самое для Laravel 5 и выше? Я пытался воспроизвести это ... Но я не могу найти, где они регистрируют аксессор «маршрута» в контейнере.
TipuZaynSultan
1
почему файл имеет расширение .pas?
Тьяго
24

Да, это возможно ..

В моем случае я добавляю метод: данные для обработки запроса /data.json в методе HTTP POST.

Это то, что я сделал.

Сначала мы расширяем Illuminate \ Routing \ ResourceRegistrar, чтобы добавить новые данные метода.

<?php

namespace App\MyCustom\Routing;

use Illuminate\Routing\ResourceRegistrar as OriginalRegistrar;

class ResourceRegistrar extends OriginalRegistrar
{
    // add data to the array
    /**
     * The default actions for a resourceful controller.
     *
     * @var array
     */
    protected $resourceDefaults = ['index', 'create', 'store', 'show', 'edit', 'update', 'destroy', 'data'];


    /**
     * Add the data method for a resourceful route.
     *
     * @param  string  $name
     * @param  string  $base
     * @param  string  $controller
     * @param  array   $options
     * @return \Illuminate\Routing\Route
     */
    protected function addResourceData($name, $base, $controller, $options)
    {
        $uri = $this->getResourceUri($name).'/data.json';

        $action = $this->getResourceAction($name, $controller, 'data', $options);

        return $this->router->post($uri, $action);
    }
}

После этого создайте новый ServiceProvider или используйте вместо него AppServiceProvider .

В загрузке метода добавьте этот код:

    public function boot()
    {
        $registrar = new \App\MyCustom\Routing\ResourceRegistrar($this->app['router']);

        $this->app->bind('Illuminate\Routing\ResourceRegistrar', function () use ($registrar) {
            return $registrar;
        });
    }

тогда :

добавьте в свой маршрут:

Route::resource('test', 'TestController');

Проверьте по php artisan route:list И вы найдете новый метод "данные"

Мохамад Рофиудин
источник
Ваше решение работает для меня .. Можете ли вы сказать мне, обнаружили ли вы какие-либо проблемы после нескольких месяцев использования этого кода?
Рикардо Вигатти,
Спасибо @RicardoVigatti. Я использовал это с laravel 5.2, и теперь я использую это в моем недавнем проекте с L5.3, и у меня нет проблем с этим. Дайте мне знать, если он у вас есть, может быть, я смогу вам помочь ..
Мохамад Рофиудин
хорошо, я реализую это в своем проекте 5.0. Решение кажется очень последовательным, но, если возникнут какие-либо проблемы, это произойдет через несколько недель.
Рикардо Вигатти,
@ MokhamadRofi'udin Я реализовал ваше решение, новый маршрут добавлен в список маршрутов, но похоже, что соответствующий метод не добавлен. Я что-то упускаю ?
Siavosh
@Siavosh просто напишите свой метод в контроллере, т.е. я добавляю данные метода (): `public function data (Request $ request) {}`
Mokhamad Rofi'udin
13
Route::resource('foo', 'FooController');
Route::controller('foo', 'FooController');

Попробуйте. Добавьте дополнительные методы, такие как getData () и т. Д. Это сработало для меня, чтобы сохранить route.php в чистоте

Хасан Джамал
источник
Яс это работает. В документации Laravel 5.1 не упоминается, что Route :: resource и Route :: controller могут использоваться вместе, скорее они упоминали о дополнении контроллеров ресурсов. Итак, это запутано. Но ваш ответ доказал, что их можно использовать вместе
Амир
Мне очень жаль, Хасан Джамал, эти двое не работают вместе. Итак, как я могу установить собственный метод публикации в контроллере, если я использую только Route :: resource
Амир
3

Использование Laravel> 5 Найдите файл web.php в папке маршрутов и добавьте свои методы

Вы можете использовать route :: resource для маршрутизации всех этих методов index, show, store, update, destroy в вашем контроллере в одной строке

Route::get('foo/bar', 'NameController@bar');
Route::resource('foo', 'NameController');
Мазен Эмбаби
источник
1

Просто добавьте к этому методу новый метод и маршрут.

В вашем контроллере:

public function foo($bar=“default)
{
      //do stuff
}

И в ваших веб-маршрутах

Route::get(“foo/{$bar}”, “MyController@foo”);

Просто убедитесь, что метод в контроллере общедоступен.

Патрик Люменус
источник
0

Раньше я определял свой маршрут как:

Route::get('foo/bar', 'FooController@bar');
Route::resource('foo', 'FooController');

Это выдало ошибку:

маршрут foo.bar не определен

А потом, погуглив, я добавил имя

Route::get('foo/bar', 'FooController@bar')->name('foo.bar');

И все работало нормально.

Прадип Пармар
источник
0

Я решаю

Создайте собственный файл маршрутизатора, расширяющий BaseRouter

// src/app/Custom/Router.php


<?php

namespace App\Custom;

use Illuminate\Routing\Router as BaseRouter;
use Illuminate\Support\Str;

class Router extends BaseRouter
{
    public function customResource($name, $controller, array $options = [])
    {
        $model = Str::singular($name); // this is optional, i need it for Route Model Binding

        $this
            ->get( // set the http methods
                $name .'/{' . $model . '}/audit',
                $controller . '@audit'
            )->name($name . '.audit');

        return $this->resource($name, $controller, $options);
    }
}

Тогда зарегистрируйтесь на src/bootstrap/app.php

$app->singleton('router', function ($app) {
    return new \App\Custom\Router($app['events'], $app);
});

И используйте его на /routes/web.php

Route::customResource(
    'entries',
    'EntryController'
);
Дев Лим
источник
-1

Это тоже неплохо работает. Нет необходимости добавлять маршруты, просто используйте метод show контроллера ресурсов следующим образом:

public function show($name){

 switch ($name){
   case 'foo':
    $this -> foo();
    break;
   case 'bar':
    $this ->bar();
    break; 
  defautlt:
    abort(404,'bad request');
    break;
 }

}
public function foo(){}
publcc function bar(){}

Я использую значение по умолчанию для вывода настраиваемой страницы ошибок.

мдамия
источник
2
Это похоже на запах настоящего кода. Я бы не хотел, чтобы мои контроллеры обрабатывали несколько действий.
RonnyKnoxville