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?

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

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

}

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'


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


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

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.


-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.


2
Esto se siente como un olor a código real. No quisiera que mis controladores manejen múltiples acciones.
— RonnyKnoxville
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.