Adicionar novos métodos a um controlador de recursos no Laravel


141

Quero saber se é possível adicionar novos métodos a um controlador de recursos no Laravel e como você o faz.

Eu sei que esses métodos são o padrão (índice, criação, armazenamento, edição, atualização, destruição). Agora eu quero adicionar métodos e rotas adicionais ao mesmo controlador.

Isso é possível?

Respostas:


261

Basta adicionar uma rota a esse método separadamente, antes de registrar o recurso:

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

7
Observe que seus novos métodos precisam ir acima do ::resourcepadrão, caso contrário, você receberá uma mensagem de erro "Nenhum resultado de consulta para o modelo".
— MPEN

Como você passaria um parâmetro como {id}? Atualmente, eu codifiquei meu método personalizado inline em routes.php (como o exemplo aqui em laravel.com/docs/5.1/routing#route-parameters ). Idealmente, eu gostaria de passar o parâmetro para executar no FooController.
— ATutorMe

1
Encontrou o problema - não estava na sintaxe da rota. Na verdade, estava em algum Middleware personalizado que estou usando! Route :: get ('foo / {id} / bar', 'FooController @ bar'); passará o método id para bar ($ id). Obrigado!
— ATutorMe

Alguém pode explicar por que a rota personalizada deve ir acima da rota do recurso ??? Eu fiz alguns testes e parece não ter nenhuma diferença entre colocar acima ou abaixo ...
— Ricardo Vigatti

3
@RicardoVigatti - O recurso registra essa rota: Route::get('foo/{id}', ...). Isso engole todas as rotas começando com fooe tendo um segmento adicional, incluindo foo/bar.
— Joseph Silber

32

Acabei de fazer isso, para adicionar um método GET "delete".

Depois de criar seus arquivos, você só precisa adicionar

'AntonioRibeiro\Routing\ExtendedRouterServiceProvider',

para 'provedores' em seu app / config.php

Edite o alias da rota neste mesmo arquivo:

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

mudando para

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

E verifique se esses arquivos estão sendo carregados automaticamente, eles devem estar em algum diretório que você possui no seu composer.json (seção "autoload").

Então você só precisa:

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

E este (veja a última linha) é o resultado se você executar php artisan routes:

lista de rotas Esses são meus arquivos de origem:

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
Você pode fornecer o mesmo para o Laravel 5 e acima? Eu tenho tentado reproduzir isso ... Mas não consigo encontrar onde eles estão registrando o Accessor 'route' no contêiner.
— TipuZaynSultan

por que o arquivo tem a extensão .pas?
— Thiago Dias

22

Sim, é possível ..

No meu caso, adiciono method: data para manipular a solicitação de /data.json no método HTTP POST.

Foi o que eu fiz.

Primeiro, estendemos o Illuminate \ Routing \ ResourceRegistrar para adicionar novos dados 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);
    }
}

Depois disso, faça seu novo ServiceProvider ou use AppServiceProvider .

Na inicialização do método , adicione 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;
        });
    }

então :

adicione à sua rota:

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

Verifique por php artisan route:list E você encontrará novo método 'dados'


Sua solução funciona para mim. Você pode me dizer se descobriu algum problema depois de alguns meses usando esse código?
— Ricardo Vigatti 19/10/16

Obrigado @RicardoVigatti. Eu usei isso desde o laravel 5.2 e agora eu uso isso no meu projeto recente com o L5.3 e não tenho nenhum problema. Deixe-me saber se você tem um, pode ser que eu possa ajudá-lo ..
— Mokhamad Rofi'udin

bom, estou implementando isso no meu projeto 5.0. A solução parece muito consistente, mas, se ocorrer algum problema, será após algumas semanas.
— Ricardo Vigatti 20/10

@ MokhamadRofi'udin Eu implementei sua solução, a nova rota é adicionada à lista de rotas, mas parece que o método correspondente não foi adicionado. Estou esquecendo de algo ?
— Siavosh 22/11

@Siavosh basta escrever o seu método no controlador ou seja, eu dados método add (): `dados da função pública (Request $ request) {}`
— Mokhamad Rofi'udin

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

Tente isso. Coloque métodos extras, como getData () etc. etc. Isso funcionou para mim para manter o route.php limpo


Yas isso funciona. A documentação do Laravel 5.1 não mencionou que o Route :: resource e o Route :: controller podem ser usados ​​juntos, mas eles mencionaram sobre a suplementação de controladores de recursos. Então isso está confuso. Mas seus ans provou que estes são podem ser usados juntos
— Amir

Sinto muito Hassan jamal, esses dois não estão trabalhando juntos. Então agora como posso definir um método de postagem personalizado em um controlador se eu usar apenas Route :: resource
— Amir

3

Usando o Laravel> 5 Encontre o arquivo web.php na pasta routes e adicione seus métodos

Você pode usar route :: resource para rotear todos esses métodos, indexar, mostrar, armazenar, atualizar, destruir no seu controlador em uma linha

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

1

Basta adicionar um novo método e uma rota a esse método.

No seu controlador:

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

E nas suas rotas da web

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

Apenas certifique-se de que o método no controlador seja público.


-1

Isso funciona muito bem também. Não há necessidade de adicionar mais rotas, basta usar o método show do controlador de recursos como este:

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

Eu uso o padrão para lançar a página de erro personalizada.


2
Parece um cheiro de código real. Eu não gostaria que meus controladores lidassem com várias ações.
— RonnyKnoxville
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.