Skip to content

Action and Routing

Michał Golon edited this page Jul 27, 2018 · 3 revisions

Action

An action in ADR is responsible for handling the request - call the domain, then call the responder and pass any required data. This simplicity allows to model action as a invokable (callable) class.

namespace App\Http\Actions;

class ShowUserAction extends Action
{
    /**
     * @param Request $request
     * @param mixed $id
     * @return \Symfony\Component\HttpFoundation\Response
     */
    public function __invoke(Request $request, $id)
    {
        // ...
    }
}

Any action should extend HydrefLab\Laravel\ADR\Action\Action class.

However, it is recommended that action extends App\Http\Actions\Action class which is already an extension of a base action class. This is situation similar to controllers - typically new controller extend App\Http\Controllers\Controller class and not its parent Illuminate\Routing\Controller class.

Any action should return either responder instance or already built response.

Creating a responder

Responder can be created/instantiated by:

  • calling responder helper method,
    namespace App\Http\Actions;
    
    class ShowUserAction extends Action
    {
        public function __invoke(Request $request, $id)
        {
            $user = User::find($id);
         
            return responder($user);
        }
    }
  • calling static ResponderFactory::create() method,
    namespace App\Http\Actions;
    
    class ShowUsersAction extends Action
    {
        public function __invoke()
        {
            $users = User::get();
         
            return ResponderFactory::create($users);
        }
    }
  • using new keyword
    namespace App\Http\Actions;
    
    class ShowUserAction extends Action
    {
        public function __invoke(Request $request, $id)
        {
            $user = User::find($id);
         
            return new ShowUserResponder($user);
        }
    }

First two methods use auto-resolving mechanism described here.

More about responders can be found here.

Routing

To register single action route, simply add:

Route::get('users/{id}', \App\Http\Actions\ShowUserAction::class);

in your routes file.

Resource actions

Actions are thin controllers. One resource controller in Laravel corresponds to 7 (!) actions. Registering routes for all the actions can be quite bothersome. There is a mechanism that allows to register your resource-like actions' routes in the same way as registering resource controller.

In your routes file, simply add:

Route::adrResource('users');

// or for API-like resource
Route::adrApiResource('users');

This will produce following result:

+--------+-----------+-------------------+---------------+------------------------------------+------------+
| Domain | Method    | URI               | Name          | Action                             | Middleware |
+--------+-----------+-------------------+---------------+------------------------------------+------------+
|        | GET|HEAD  | users             | users.index   | App\Http\Actions\IndexUsersAction  | web        |
|        | POST      | users             | users.store   | App\Http\Actions\StoreUserAction   | web        |
|        | GET|HEAD  | users/create      | users.create  | App\Http\Actions\CreateUserAction  | web        |
|        | GET|HEAD  | users/{user}      | users.show    | App\Http\Actions\ShowUserAction    | web        |
|        | PUT|PATCH | users/{user}      | users.update  | App\Http\Actions\UpdateUserAction  | web        |
|        | DELETE    | users/{user}      | users.destroy | App\Http\Actions\DestroyUserAction | web        |
|        | GET|HEAD  | users/{user}/edit | users.edit    | App\Http\Actions\EditUserAction    | web        |
+--------+-----------+-------------------+---------------+------------------------------------+------------+

adrResource and adrApiResource are route's macros and they can be used in the same way as resource controller's routes registration, i.e. pass namespace or additional route options:

// controller approach
Route::resource('users', 'MyNamespace/UsersController', ['except' => ['destroy']]);

// action approach
Route::adrResource('users', 'MyNamespace', ['except' => ['destroy']]);

The only difference here is that in controller approach namespace or partial namespace of the controller is passed, while in action approach namespace or partial namespace of all the actions is specified.

If namespace is not passed during actions' routes registration, namespace from configuration is taken into consideration.

Resource action class names resolving

The package adds one default resource action's class name resolver.

Resource action's class name is composed of:

  • namespace,
  • action type (index, store, etc.),
  • resource name and
  • postfix (from configuration).

If actions will be placed or named differently, new resolver(s) should/can be added.

It is possible by calling ActionResolver::extend() method in any of the application service providers:

ActionResolver::extend(new MyCustomActionResolver());

// or

ActionResolver::extend(function(string $namespace, string $resource, string $actionType) {
    // my custom resolver content here
});

Resolvers are run in the reverse order as they were added.

Clone this wiki locally