Agregue nuevos métodos a un controlador de recursos en Laravel

141

Quiero saber si es posible agregar nuevos métodos a un controlador de recursos en Laravel y cómo lo hace.

Sé que estos métodos son los predeterminados (indexar, crear, almacenar, editar, actualizar, destruir). Ahora quiero agregar métodos y rutas adicionales al mismo controlador.

¿Es eso posible?

usuario2403824
fuente

Respuestas:

261

Simplemente agregue una ruta a ese método por separado, antes de registrar el recurso:

Route::get('foo/bar', 'FooController@bar');
Route::resource('foo', 'FooController');
Joseph Silber
fuente
77
Tenga en cuenta que sus nuevos métodos tienen que ir por encima de lo ::resourcecontrario, recibirá un mensaje de error, "No hay resultados de consulta para el modelo".
mpen
¿Cómo pasarías un parámetro como {id}? Actualmente he codificado mi método personalizado en línea en routes.php (como en el ejemplo aquí laravel.com/docs/5.1/routing#route-parameters ). Idealmente, me gustaría pasar el parámetro para ejecutar en FooController.
ATutorMe
1
Encontró el problema: no estaba en la sintaxis de la ruta. ¡De hecho, estaba en un Middleware personalizado que estoy usando! Ruta :: get ('foo / {id} / bar', 'FooController @ bar'); pasará el método id a bar ($ id). ¡Gracias!
ATutorMe
¿Alguien puede explicar por qué la ruta personalizada debe ir por encima de la ruta de recursos? He hecho algunas pruebas y parece que no hay diferencia entre poner arriba o abajo ...
Ricardo Vigatti
3
@RicardoVigatti - El recurso registra esta ruta: Route::get('foo/{id}', ...). Esto traga todas las rutas que comienzan fooy tienen un segmento adicional, incluido foo/bar.
Joseph Silber
32

Acabo de hacer eso, para agregar un método GET "eliminar".

Después de crear sus archivos, solo necesita agregar

'AntonioRibeiro\Routing\ExtendedRouterServiceProvider',

a 'proveedores' en su aplicación / config.php

Edite el alias de ruta en este mismo archivo:

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

cambiándolo a

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

Y asegúrese de que esos archivos se carguen automáticamente, deben estar en algún directorio que tenga en su composer.json (sección "carga automática").

Entonces solo necesitas:

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

Y esto (mira la última línea) es el resultado si ejecutas php artisan routes:

lista de rutas Esos son mis archivos fuente:

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
fuente
3
¿Puede proporcionar lo mismo para Laravel 5 y superior? He estado tratando de reproducir esto ... Pero parece que no puedo encontrar dónde están registrando el Accesor de 'ruta' en el contenedor.
TipuZaynSultan
¿Por qué el archivo tiene la extensión .pas?
Thiago Dias
22

Si, es posible ...

En mi caso, agrego método: datos para manejar la solicitud de /data.json en el método HTTP POST.

Esto es lo que hice.

Primero ampliamos Illuminate \ Routing \ ResourceRegistrar para agregar nuevos datos de método

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

Después de eso, cree su nuevo ServiceProvider o use AppServiceProvider en su lugar.

En el arranque del método , agregue este código:

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

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

luego :

agregar a su ruta:

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

Verifique php artisan route:list y encontrará un nuevo método 'datos'

Mokhamad Rofi'udin
fuente
Su solución funciona para mí. ¿Puede decirme si descubrió algún problema después de algunos meses usando este código?
Ricardo Vigatti
Gracias @RicardoVigatti. Lo utilicé desde laravel 5.2 y ahora lo uso en mi proyecto reciente con L5.3 y no tengo ningún problema. Avíseme si tiene uno, tal vez pueda ayudarlo ...
Mokhamad Rofi'udin
bueno, estoy implementando esto en mi proyecto 5.0. La solución parece muy consistente, pero, si surge algún problema, será después de algunas semanas.
Ricardo Vigatti
@ MokhamadRofi'udin He implementado su solución, la nueva ruta se agrega a la lista de rutas, pero parece que no se agregó el método correspondiente. Me estoy perdiendo de algo ?
Siavosh
@Siavosh solo escribe su método en el controlador, es decir, agrego datos del método (): `datos de función pública (Solicitar $ solicitud) {}`
Mokhamad Rofi'udin
13
Route::resource('foo', 'FooController');
Route::controller('foo', 'FooController');

Pruébelo. Ponga métodos adicionales como getData () etc. etc. Esto me funcionó para mantener limpio route.php

Hassan Jamal
fuente
Yas esto funciona. La documentación de Laravel 5.1 no mencionó que Route :: resource y Route :: controller se pueden usar juntos, sino que mencionaron acerca de los Controladores de recursos complementarios. Entonces esto es confuso. Pero su respuesta demostró que se pueden usar juntos
Amir el
Lo siento Hassan Jamal, estos dos no están trabajando juntos. Entonces, ¿cómo puedo configurar un método de publicación personalizado en un controlador si solo uso Route :: resource
Amir
3

Usando Laravel> 5 Encuentra el archivo web.php en la carpeta de rutas agrega tus métodos

Puede usar route :: resource para enrutar todos estos métodos indexar, mostrar, almacenar, actualizar, destruir en su controlador en una línea

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

Simplemente agregue un nuevo método y una ruta a ese método.

En tu controlador:

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

Y en tus rutas web

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

Solo asegúrese de que el método en el controlador sea público.

Patrick Lumenus
fuente
-1

Esto funciona bastante bien también. No es necesario agregar más rutas, solo use el método show del controlador de recursos de esta manera:

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 el valor predeterminado para lanzar una página de error personalizada.

mdamia
fuente
2
Esto se siente como un olor a código real. No quisiera que mis controladores manejen múltiples acciones.
RonnyKnoxville