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?

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

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

}

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'


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


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

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.


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


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


2
Cela ressemble à une vraie odeur de code. Je ne voudrais pas que mes contrôleurs gèrent plusieurs actions.
RonnyKnoxville
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.