Ajouter de nouvelles méthodes à un contrôleur de ressources dans Laravel

141

Je veux savoir s'il est possible d'ajouter de nouvelles méthodes à un contrôleur de ressources dans Laravel et comment vous le faites.

Je sais que ces méthodes sont les méthodes par défaut (indexer, créer, stocker, modifier, mettre à jour, détruire). Maintenant, je veux ajouter des méthodes et des routes supplémentaires au même contrôleur.

Est-ce possible?

user2403824
la source

Réponses:

262

Ajoutez simplement une route à cette méthode séparément, avant d'enregistrer la ressource:

Route::get('foo/bar', 'FooController@bar');
Route::resource('foo', 'FooController');
Joseph Silber
la source
7
Notez que vos nouvelles méthodes doivent aller au - dessus du ::resourcesinon vous obtenez un message d'erreur, "Aucun résultat de requête pour le modèle".
mpen
Comment passeriez-vous un paramètre comme {id}? Actuellement, j'ai codé ma méthode personnalisée en ligne dans routes.php (comme l'exemple ici laravel.com/docs/5.1/routing#route-parameters ). Idéalement, je voudrais passer le paramètre à exécuter dans FooController.
ATutorMe
1
J'ai trouvé le problème - n'était pas dans la syntaxe Route. Était en fait dans un middleware personnalisé que j'utilise! Route :: get ('foo / {id} / bar', 'FooController @ bar'); passera l'id à la méthode bar ($ id). Merci!
ATutorMe
Quelqu'un peut-il expliquer pourquoi la route personnalisée doit aller au-dessus de la route des ressources ??? J'ai fait quelques tests et semble n'avoir aucune différence entre mettre au-dessus ou en dessous ...
Ricardo Vigatti
3
@RicardoVigatti - La ressource enregistre cette voie: Route::get('foo/{id}', ...). Cela avale tous les itinéraires commençant par fooet ayant un segment supplémentaire, y compris foo/bar.
Joseph Silber
32

Je viens de faire cela, pour ajouter une méthode GET "delete".

Après avoir créé vos fichiers, il vous suffit d'ajouter

'AntonioRibeiro\Routing\ExtendedRouterServiceProvider',

aux 'fournisseurs' dans votre application / config.php

Modifiez l'alias d'itinéraire dans ce même fichier:

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

le changer en

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

Et assurez-vous que ces fichiers sont en cours de chargement automatique, ils doivent être dans un répertoire que vous avez dans votre composer.json (section "autoload").

Ensuite, il vous suffit de:

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

Et ceci (regardez la dernière ligne) est le résultat si vous exécutez php artisan routes:

liste des itinéraires Ce sont mes fichiers source:

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
la source
3
Pouvez-vous s'il vous plaît fournir la même chose pour Laravel 5 et ci-dessus? J'ai essayé de reproduire ceci ... Mais je n'arrive pas à trouver où ils enregistrent l'accesseur «route» dans le conteneur.
TipuZaynSultan
pourquoi le fichier a l'extension .pas?
Thiago Dias
22

Ouais, c'est possible ...

Dans mon cas, j'ajoute method: data pour gérer la demande de /data.json dans la méthode HTTP POST.

C'est ce que j'ai fait.

Nous étendons d'abord Illuminate \ Routing \ ResourceRegistrar pour ajouter de nouvelles données de méthode

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

Après cela, créez votre nouveau ServiceProvider ou utilisez plutôt AppServiceProvider .

Dans le démarrage de la méthode , ajoutez ce code:

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

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

puis :

ajouter à votre itinéraire:

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

Check by php artisan route:list Et vous trouverez une nouvelle méthode 'data'

Mokhamad Rofi'udin
la source
Votre solution fonctionne pour moi. Pouvez-vous me dire si vous avez découvert un problème après quelques mois d'utilisation de ce code?
Ricardo Vigatti
Merci @RicardoVigatti. J'ai utilisé ceci depuis laravel 5.2 et maintenant je l'utilise dans mon récent projet avec L5.3 et je n'ai aucun problème avec cela. Faites-moi savoir si vous en avez un, je peux peut-être vous aider ..
Mokhamad Rofi'udin
gentil, j'implémente ceci dans mon projet 5.0. La solution semble très cohérente, mais si un problème survient, ce sera après quelques semaines.
Ricardo Vigatti
@ MokhamadRofi'udin J'ai implémenté votre solution, la nouvelle route est ajoutée à la liste des routes mais il semble que la méthode correspondante ne soit pas ajoutée. Est-ce que je manque quelque chose?
Siavosh
@Siavosh écrivez simplement votre méthode dans le contrôleur, c'est-à-dire que j'ajoute des données de méthode (): `public function data (Request $ request) {}`
Mokhamad Rofi'udin
13
Route::resource('foo', 'FooController');
Route::controller('foo', 'FooController');

Essayez ceci. Mettez-vous des méthodes supplémentaires comme getData (), etc. Cela a fonctionné pour moi pour garder route.php propre

Hassan Jamal
la source
Yas cela fonctionne. La documentation de Laravel 5.1 n'a pas mentionné que Route :: resource et Route :: controller peuvent être utilisés ensemble plutôt qu'ils ont mentionné la supplémentation des contrôleurs de ressources. Donc c'est confus. Mais votre an a prouvé que ceux-ci peuvent être utilisés ensemble
Amir
Je suis désolé Hassan Jamal, ces deux-là ne travaillent pas ensemble. Alors maintenant, comment puis-je définir une méthode de publication personnalisée dans un contrôleur si j'utilise uniquement Route :: resource
Amir
3

Utilisation de Laravel> 5 Recherchez le fichier web.php dans le dossier routes ajoutez vos méthodes

Vous pouvez utiliser route :: resource pour router toutes ces méthodes index, show, store, update, destroy dans votre contrôleur en une seule ligne

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

Ajoutez simplement une nouvelle méthode et une route vers cette méthode.

Dans votre contrôleur:

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

Et dans vos routes web

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

Assurez-vous simplement que la méthode du contrôleur est publique.

Patrick Lumenus
la source
0

précédemment j'ai défini mon itinéraire comme
Route :: get ('foo / bar', 'FooController @ bar');
Route :: resource ('foo', 'FooController');

cela a donné une erreur: la route foo.bar n'est pas définie

et après quelques recherches sur Google, j'ai ajouté le nom
Route :: get ('foo / bar', 'FooController @ bar') -> nom ('foo.bar');

et cela a bien fonctionné.

Pradeep Parmar
la source
-1

Cela fonctionne très bien aussi. Pas besoin d'ajouter plus de routes, utilisez simplement la méthode show du contrôleur de ressources comme ceci:

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

J'utilise la valeur par défaut pour lancer une page d'erreur personnalisée.

mdamia
la source
2
Cela ressemble à une vraie odeur de code. Je ne voudrais pas que mes contrôleurs gèrent plusieurs actions.
RonnyKnoxville