Dodaj nowe metody do kontrolera zasobów w Laravel

141

Chcę wiedzieć, czy jest możliwe dodanie nowych metod do kontrolera zasobów w Laravel i jak to się robi.

Wiem, że te metody są domyślne (indeksuj, twórz, przechowuj, edytuj, aktualizuj, niszcz). Teraz chcę dodać dodatkowe metody i trasy do tego samego kontrolera.

Czy to jest możliwe?

user2403824
źródło

Odpowiedzi:

261

Po prostu dodaj osobno trasę do tej metody, zanim zarejestrujesz zasób:

Route::get('foo/bar', 'FooController@bar');
Route::resource('foo', 'FooController');
Joseph Silber
źródło
7
Zwróć uwagę, że nowe metody muszą być wyższe niż w ::resourceprzeciwnym razie zostanie wyświetlony komunikat o błędzie „Brak wyników zapytania dla modelu”.
mpen
Jak przekazałbyś parametr taki jak {id}? Obecnie zakodowałem swoją niestandardową metodę inline w route.php (tak jak w przykładzie laravel.com/docs/5.1/routing#route-parameters ). Idealnie chciałbym przekazać parametr do uruchomienia w FooController.
ATutorMe
1
Znaleziono problem - nie ma go w składni trasy. W rzeczywistości było to w jakimś niestandardowym oprogramowaniu pośrednim, którego używam! Route :: get ('foo / {id} / bar', 'FooController @ bar'); przekaże id do metody bar ($ id). Dzięki!
ATutorMe
Czy ktoś może wyjaśnić, dlaczego trasa niestandardowa powinna przebiegać powyżej trasy zasobów? Zrobiłem kilka testów i wydaje mi się, że nie ma różnicy między umieszczaniem powyżej lub poniżej ...
Ricardo Vigatti
3
@RicardoVigatti - Zasób rejestruje tę drogę: Route::get('foo/{id}', ...). To pochłania wszystkie trasy zaczynające się od fooi mające jeden dodatkowy segment, w tym foo/bar.
Joseph Silber
32

Właśnie to zrobiłem, aby dodać metodę GET "usuń".

Po utworzeniu plików wystarczy dodać

'AntonioRibeiro\Routing\ExtendedRouterServiceProvider',

do „dostawców” w twojej aplikacji / config.php

Edytuj alias trasy w tym samym pliku:

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

zmiana na

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

Upewnij się, że te pliki są ładowane automatycznie, muszą znajdować się w jakimś katalogu, który masz w swoim pliku composer.json (sekcja "autoload").

Następnie wystarczy:

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

A to (spójrz na ostatnią linię) jest wynikiem, jeśli uruchomisz php artisan routes:

lista tras To są moje pliki źródłowe:

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');
    }

}
Antonio Carlos Ribeiro
źródło
3
Czy możesz podać to samo dla Laravel 5 i nowszych? Próbowałem to odtworzyć ... Ale nie mogę znaleźć miejsca, w którym rejestrują Accessor „trasy” w kontenerze.
TipuZaynSultan
dlaczego plik ma rozszerzenie .pas?
Thiago Dias
22

Tak, to możliwe ...

W moim przypadku dodaję metodę: dane do obsługi żądania /data.json w metodzie HTTP POST.

To co zrobiłem.

Najpierw rozszerzamy Illuminate \ Routing \ ResourceRegistrar, aby dodać nowe dane metody

<?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);
    }
}

Następnie utwórz nowy ServiceProvider lub zamiast tego użyj AppServiceProvider .

Podczas rozruchu metody dodaj ten kod:

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

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

następnie :

dodaj do swojej trasy:

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

Sprawdź przez php artisan route:list A znajdziesz nową metodę 'dane'

Mokhamad Rofi'udin
źródło
Twoje rozwiązanie działa dla mnie… Czy możesz mi powiedzieć, czy po kilku miesiącach używania tego kodu odkryłeś jakiś problem?
Ricardo Vigatti
Dzięki @RicardoVigatti. Używałem tego od wersji laravel 5.2, a teraz używam tego w moim ostatnim projekcie z L5.3 i nie mam z tym problemu. Daj mi znać, jeśli taki masz, może mogę ci pomóc ..
Mokhamad Rofi'udin
nieźle, wdrażam to w moim projekcie 5.0. Rozwiązanie wydaje się bardzo spójne, ale jeśli wystąpi jakikolwiek problem, nastąpi to po kilku tygodniach.
Ricardo Vigatti
@ MokhamadRofi'udin Zaimplementowałem Twoje rozwiązanie, nowa trasa jest dodawana do listy tras, ale wygląda na to, że nie dodano odpowiedniej metody. Czy coś mi brakuje?
Siavosh
@Siavosh po prostu napisz swoją metodę w kontrolerze, tj. Dodaję metodę data (): `public function data (Request $ request) {}`
Mokhamad Rofi'udin
13
Route::resource('foo', 'FooController');
Route::controller('foo', 'FooController');

Spróbuj. Dodaj dodatkowe metody, takie jak getData () itp., Itp. Pomogło mi to zachować porządek w route.php

Hassan Jamal
źródło
Tak, to działa. Laravel 5.1 Documentation nie wspomniał, że Route :: resource i Route :: controller mogą być używane razem, a raczej wspomnieli o uzupełnianiu kontrolerów zasobów. Więc to jest zdezorientowane. Ale twoje odpowiedzi udowodniły, że można ich używać razem
Amir
Przepraszam Hassan jamal, ta dwójka nie pracuje razem. Więc teraz, jak mogę ustawić niestandardową metodę wpisu w kontrolerze, jeśli używam tylko Route :: resource
Amir
3

Korzystanie z Laravel> 5 Znajdź plik web.php w folderze tras i dodaj swoje metody

Możesz użyć route :: resource do kierowania wszystkich tych metod do indeksowania, pokazywania, przechowywania, aktualizowania, niszczenia w kontrolerze w jednej linii

Route::get('foo/bar', 'NameController@bar');
Route::resource('foo', 'NameController');
Mazen Embaby
źródło
1

Po prostu dodaj nową metodę i trasę do tej metody.

W kontrolerze:

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

Oraz w Twoich trasach internetowych

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

Upewnij się tylko, że metoda w kontrolerze jest publiczna.

Patrick Lumenus
źródło
-1

To też działa całkiem nieźle. Nie ma potrzeby dodawania kolejnych tras, wystarczy użyć metody show kontrolera zasobów w następujący sposób:

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(){}

Używam wartości domyślnej, aby wrzucić niestandardową stronę błędu.

mdamia
źródło
2
To jak prawdziwy zapach kodu. Nie chciałbym, aby moje kontrolery obsługiwały wiele akcji.
RonnyKnoxville