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.