Fügen Sie einem Ressourcencontroller in Laravel neue Methoden hinzu

141

Ich möchte wissen, ob es möglich ist, einem Ressourcencontroller in Laravel neue Methoden hinzuzufügen, und wie Sie dies tun.

Ich weiß, dass diese Methoden die Standardeinstellung sind (Indexieren, Erstellen, Speichern, Bearbeiten, Aktualisieren, Zerstören). Jetzt möchte ich dem gleichen Controller zusätzliche Methoden und Routen hinzufügen.

Ist das möglich?

user2403824
quelle

Antworten:

261

Fügen Sie dieser Methode einfach eine Route separat hinzu, bevor Sie die Ressource registrieren:

Route::get('foo/bar', 'FooController@bar');
Route::resource('foo', 'FooController');
Joseph Silber
quelle
7
Beachten Sie, dass Ihre neuen Methoden über die ::resourcehinausgehen müssen, da sonst die Fehlermeldung "Keine Abfrageergebnisse für Modell" angezeigt wird.
Mpen
Wie würden Sie einen Parameter wie {id} übergeben? Derzeit habe ich meine benutzerdefinierte Methode inlines.php inline codiert (wie im Beispiel hier laravel.com/docs/5.1/routing#route-parameters ). Idealerweise möchte ich den Parameter übergeben, der in FooController ausgeführt werden soll.
ATutorMe
1
Fand das Problem - war nicht in der Route-Syntax. War tatsächlich in einer benutzerdefinierten Middleware, die ich verwende! Route :: get ('foo / {id} / bar', 'FooController @ bar'); Übergibt die ID an die bar ($ id) -Methode. Vielen Dank!
ATutorMe
Kann jemand erklären, warum die benutzerdefinierte Route über die Ressourcenroute hinausgehen sollte? Ich habe einige Tests durchgeführt und scheint keinen Unterschied zwischen oben und unten zu haben ...
Ricardo Vigatti
3
@ RicardoVigatti - Die Ressource registriert diese Route : Route::get('foo/{id}', ...). Dies verschluckt alle Routen, beginnend mit foound mit einem zusätzlichen Segment, einschließlich foo/bar.
Joseph Silber
32

Ich habe das gerade getan, um eine GET "delete" -Methode hinzuzufügen.

Nach dem Erstellen Ihrer Dateien müssen Sie nur noch hinzufügen

'AntonioRibeiro\Routing\ExtendedRouterServiceProvider',

zu 'Providern' in Ihrer App / config.php

Bearbeiten Sie den Routenalias in derselben Datei:

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

Ändern in

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

Und stellen Sie sicher, dass diese Dateien automatisch geladen werden. Sie müssen sich in einem Verzeichnis befinden, das Sie in Ihrer composer.json (Abschnitt "Autoload") haben.

Dann müssen Sie nur noch:

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

Und dies (siehe letzte Zeile) ist das Ergebnis, wenn Sie ausführen php artisan routes:

Routenliste Das sind meine Quelldateien:

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
quelle
3
Können Sie bitte dasselbe für Laravel 5 und höher bereitstellen? Ich habe versucht, dies zu reproduzieren ... Aber ich kann anscheinend nicht finden, wo sie den 'Route'-Accessor im Container registrieren.
TipuZaynSultan
Warum hat die Datei die Erweiterung .pas?
Thiago Dias
22

Ja, es ist möglich ..

In meinem Fall füge ich method: data hinzu, um die Anforderung für /data.json in der HTTP-POST-Methode zu verarbeiten.

Das habe ich getan.

Zunächst erstreckt wir Illuminate \ Routing \ ResourceRegistrar neue Methode hinzuzufügen , Daten

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

Erstellen Sie danach Ihren neuen ServiceProvider oder verwenden Sie stattdessen AppServiceProvider .

Fügen Sie beim Starten der Methode diesen Code hinzu:

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

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

dann :

zu deiner Route hinzufügen:

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

Check by php artisan route:list Und Sie finden neue Methode 'Daten'

Mokhamad Rofi'udin
quelle
Ihre Lösung funktioniert für mich. Können Sie mir sagen, ob Sie nach einigen Monaten mit diesem Code ein Problem entdeckt haben?
Ricardo Vigatti
Danke @RicardoVigatti. Ich habe dies seit Laravel 5.2 verwendet und jetzt verwende ich dies in meinem letzten Projekt mit L5.3 und habe kein Problem damit. Lassen Sie mich wissen, wenn Sie eine haben, vielleicht kann ich Ihnen helfen ..
Mokhamad Rofi'udin
Schön, ich implementiere dies in meinem 5.0-Projekt. Die Lösung scheint sehr konsistent zu sein, aber wenn ein Problem auftritt, wird es nach einigen Wochen sein.
Ricardo Vigatti
@ MokhamadRofi'udin Ich habe Ihre Lösung implementiert. Die neue Route wird zur Routenliste hinzugefügt, aber anscheinend wird die entsprechende Methode nicht hinzugefügt. Vermisse ich etwas
Siavosh
@Siavosh schreiben Sie einfach Ihre Methode in Controller, dh ich füge Methodendaten hinzu (): `öffentliche Funktionsdaten (Request $ request) {}`
Mokhamad Rofi'udin
13
Route::resource('foo', 'FooController');
Route::controller('foo', 'FooController');

Probieren Sie es aus. Geben Sie zusätzliche Methoden wie getData () usw. usw. ein. Dies hat bei mir funktioniert, um route.php sauber zu halten

Hassan Jamal
quelle
Ja, das funktioniert. In der Laravel 5.1-Dokumentation wurde nicht erwähnt, dass Route :: resource und Route :: controller zusammen verwendet werden können, sondern es wurde über das Ergänzen von Resource Controllern gesprochen. Das ist also verwirrt. Aber Ihre Ans haben bewiesen, dass diese zusammen verwendet werden können
Amir
Es tut mir leid, Hassan Jamal, diese beiden arbeiten nicht zusammen. Wie kann ich nun eine benutzerdefinierte Post-Methode in einem Controller festlegen, wenn ich nur Route :: resource
Amir vom
3

Verwenden von Laravel> 5 Suchen Sie die Datei web.php im Ordner "Routen" und fügen Sie Ihre Methoden hinzu

Sie können route :: resource verwenden, um alle diese Methoden in einer Zeile zu indizieren, anzuzeigen, zu speichern, zu aktualisieren und in Ihrem Controller zu zerstören

Route::get('foo/bar', 'NameController@bar');
Route::resource('foo', 'NameController');
Mazen Embaby
quelle
1

Fügen Sie einfach eine neue Methode und eine Route zu dieser Methode hinzu.

In Ihrem Controller:

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

Und in Ihren Webrouten

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

Stellen Sie nur sicher, dass die Methode im Controller öffentlich ist.

Patrick Lumenus
quelle
-1

Das funktioniert auch ziemlich gut. Sie müssen keine weiteren Routen hinzufügen. Verwenden Sie einfach die show-Methode des Ressourcencontrollers wie folgt:

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

Ich verwende die Standardeinstellung, um eine benutzerdefinierte Fehlerseite zu werfen.

mdamia
quelle
2
Das fühlt sich an wie ein echter Codegeruch. Ich möchte nicht, dass meine Controller mehrere Aktionen ausführen.
RonnyKnoxville