Aggiungi nuovi metodi a un controller di risorse in Laravel


141

Voglio sapere se è possibile aggiungere nuovi metodi a un controller di risorse in Laravel e come lo si fa.

So che questi metodi sono quelli predefiniti (indicizza, crea, archivia, modifica, aggiorna, distruggi). Ora voglio aggiungere metodi e percorsi aggiuntivi allo stesso controller.

È possibile?

Risposte:


262

Basta aggiungere un percorso a quel metodo separatamente, prima di registrare la risorsa:

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

7
Nota che i nuovi metodi devono passare sopra il ::resourcealtrimenti si ottiene un messaggio di errore, "Nessun risultato di query per il modello".
mpen

Come passeresti un parametro come {id}? Attualmente ho codificato il mio metodo personalizzato in route.php (come nell'esempio qui laravel.com/docs/5.1/routing#route-parameters ). Idealmente, vorrei passare il parametro per l'esecuzione in FooController.
ATutorMe

1
Trovato il problema - non era nella sintassi del percorso. In realtà era in un middleware personalizzato che sto usando! Route :: get ('foo / {id} / bar', 'FooController @ bar'); passerà l'id alla barra ($ id) metodo. Grazie!
ATutorMe

Qualcuno può spiegare perché il percorso personalizzato dovrebbe andare al di sopra del percorso delle risorse ??? Ho fatto alcuni test e sembra non avere alcuna differenza tra mettere sopra o sotto ...
Ricardo Vigatti

3
@RicardoVigatti - La risorsa registra questo percorso: Route::get('foo/{id}', ...). Ciò ingoia tutte le rotte che iniziano con fooe con un segmento aggiuntivo, incluso foo/bar.
Joseph Silber,

32

L'ho appena fatto, per aggiungere un metodo GET "elimina".

Dopo aver creato i tuoi file, devi solo aggiungere

'AntonioRibeiro\Routing\ExtendedRouterServiceProvider',

a "provider" nella tua app / config.php

Modifica l'alias del percorso in questo stesso file:

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

cambiandolo in

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

E assicurati che i file vengano caricati automaticamente, devono trovarsi in una directory che hai nel tuo composer.json (sezione "autoload").

Quindi devi solo:

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

E questo (guarda l'ultima riga) è il risultato se esegui php artisan routes:

elenco dei percorsi Questi sono i miei file di origine:

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
Puoi fornire lo stesso per Laravel 5 e versioni successive? Ho cercato di riprodurre questo ... Ma non riesco a trovare dove stiano registrando l'accessor "route" nel contenitore.
TipuZaynSultan,

perché il file ha l'estensione .pas?
Thiago Dias,

22

Sì, è possibile ..

Nel mio caso aggiungo metodo: dati per gestire la richiesta di /data.json nel metodo POST HTTP.

Questo è quello che ho fatto.

Innanzitutto estendiamo Illuminate \ Routing \ ResourceRegistrar per aggiungere nuovi dati di metodo

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

Successivamente, crea il tuo nuovo ServiceProvider o usa invece AppServiceProvider .

Nell'avvio del metodo , aggiungi questo codice:

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

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

poi :

aggiungi al tuo percorso:

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

Controlla da php artisan route:list E troverai nuovi 'dati' metodo


La tua soluzione funziona per me. Puoi dirmi se hai scoperto qualche problema dopo alcuni mesi usando questo codice?
Ricardo Vigatti,

Grazie @RicardoVigatti. L'ho usato da Laravel 5.2 e ora lo uso nel mio recente progetto con L5.3 e non ho alcun problema. Fammi sapere se ne hai uno, forse posso aiutarti ...
Mokhamad Rofi'udin,

bello, lo sto implementando nel mio progetto 5.0. La soluzione sembra molto coerente, ma, in caso di problemi, lo sarà dopo alcune settimane.
Ricardo Vigatti,

@ MokhamadRofi'udin Ho implementato la tua soluzione, il nuovo percorso viene aggiunto all'elenco percorsi ma sembra che il metodo corrispondente non sia stato aggiunto. Mi sto perdendo qualcosa ?
Siavosh,

@Siavosh basta scrivere il tuo metodo nel controller, cioè aggiungo i dati del metodo (): `dati di funzione pubblica (Request $ request) {}`
Mokhamad Rofi'udin,

13
Route::resource('foo', 'FooController');
Route::controller('foo', 'FooController');

Provalo. Metti metodi extra come getData () ecc. Questo ha funzionato per me per mantenere pulito route.php


Sì, funziona. La documentazione di Laravel 5.1 non ha menzionato il fatto che Route :: resource e Route :: controller possono essere usati insieme, piuttosto hanno menzionato l'integrazione dei controller di risorse. Quindi questo è confuso. Ma il tuo ans ha dimostrato che questi possono essere usati insieme
Amir

Mi dispiace Hassan Jamal, questi due non stanno lavorando insieme. Quindi ora come posso impostare un metodo di post personalizzato in un controller se uso solo Route :: resource
Amir

3

Utilizzo di Laravel> 5 Trova il file web.php nella cartella route e aggiungi i tuoi metodi

È possibile utilizzare route :: resource per instradare tutti questi metodi indicizzando, mostrando, archiviando, aggiornando, distruggendo nel controller in una riga

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

1

Basta aggiungere un nuovo metodo e un percorso a quel metodo.

Nel tuo controller:

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

E nei tuoi percorsi web

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

Assicurati solo che il metodo nel controller sia pubblico.


-1

Anche questo funziona abbastanza bene. Non è necessario aggiungere più percorsi, basta usare il metodo show del controller delle risorse in questo modo:

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

Uso l'impostazione predefinita per lanciare la pagina di errore personalizzata.


2
Sembra un vero odore di codice. Non vorrei che i miei controller gestissero più azioni.
RonnyKnoxville,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.