⚡️ Laravel components that take care of one specific task
MIT License
Bot releases are hidden (Show)
Published by lorisleiva about 4 years ago
🚑 Fixes ignored default values in handle method (#66)
Published by lorisleiva about 4 years ago
🚑 Bug fix
Published by lorisleiva about 4 years ago
⬆️ Add support for Laravel 8
Published by lorisleiva about 4 years ago
📝 Use expectsJson
instead of wantsJson
to determine if we should use jsonResponse
for Actions as controllers.
Published by lorisleiva over 4 years ago
🖼 Fix paths on Windows (https://github.com/lorisleiva/laravel-actions/commit/667fe744ad7b2c724535d0797026424636c45456)
Published by lorisleiva over 4 years ago
This release slightly adjusts the dependency injection logic by supporting nullable typehints. Let's go through a few examples to understand what that really means.
Assuming $service
is not an attribute of this action, prior to this version, it would have resolved the MyInjectedService
class from the container even though it's an optional typehint (notice the ?
prefix). Now, it will not even try to resolve it from the container. This mechanism can be helpful to turn dependency injection off for certain arguments.
class MyAction extends Action
{
public function handle(?MyInjectedService $service)
{
// ...
}
};
The reason behind this change is to make sure Laravel Actions does not try to become too intrusive when resolving the arguments of your methods.
Consider the example below where the User model is typehinted but marked as nullable. Prior to this version, Laravel Actions would have thrown an exception if the provided user identifier did not successfully retrieve a user from the database. Now, it will return null
instead of throwing an exception if the user cannot be found via the provided identifier.
class MyAction extends Action
{
public function handle(?User $user)
{
// if $user is "1" and User::find(1) exists, it returns the fetched model.
// if $user is "42" and User::find(42) does not exist, it returns null instead of throwing an exception
// if $user is null, it returns null instead of throwing an exception
}
};
The reason behind this change is to allow a more flexible route model binding.
Whilst these changes can break some existing code (hence the jump to 1.1
) it is very unlikely that it will. Chances are, if you were marking a typehint as nullable before, you were already planning for that argument to be null
.
Published by lorisleiva over 4 years ago
📝 Add controllerMiddleware
method to avoid conflicts with job middleware. If the controllerMiddleware
is not provided, it falls back to using middleware
to avoid breaking changes.
Published by lorisleiva over 4 years ago
🤝 Add support for custom implicit route bindings (e.g. /articles/{article:slug}
) and nested route bindings (e.g. /users/{users}/articles/{article:slug}
) for Laravel 7 only (see Laravel documentation).
Published by lorisleiva over 4 years ago
Make handle
method optional. This allows for actions acting as pure authorisation or validation guards as well as actions that simply need a response
method to render some view. (See #39)
Published by lorisleiva over 4 years ago
Adjust PHPStorm annotations to allow for custom getAttributeFromConstructor
logic.
Published by lorisleiva over 4 years ago
You can now run actions as commands by simply providing the commandSignature
static property.
class PublishANewArticle extends Action
{
protected static $commandSignature = 'make:article {title} {body}';
protected static $commandDescription = 'Publishes a new article';
// ...
}
You can now register your routes directly in the routes
static method of your actions.
class GetArticlesFromAuthor extends Action
{
public static function routes(Router $router)
{
$router->get('author/{author}/articles', static::class);
}
public function handle(User $author)
{
return $author->articles;
}
}
Imagine the following GetItineraryInstructions
action that returns an array of strings given an address and a transportation mode. Here is how you would need to instantiate this action:
$action = new GetItineraryInstructions([
'address' => $address,
'mode' => 'driving',
]);
However, in this particular case, this action will always take an address
and a mode
attribute so wouldn't it be better if we could just write this instead?
$action = new GetItineraryInstructions($address, 'driving');
Well, starting from v1.0, you can. All you need to do to make this work is to define your custom logic in the getAttributesFromConstructor
method. See the documentation to learn more about this.
Note that, this will also work with the run
and dispatch
static methods.
// As an object.
GetItineraryInstructions::run($address, 'driving');
// As a job.
GetItineraryInstructions::dispatch($address, 'driving');
# In your composer.json
"lorisleiva/laravel-actions": "^1.0",
composer update lorisleiva/laravel-actions
The register
method has been renamed initialized
. It will be called every single time an action is instantiated no matter how it is running. (See The lifecycle of an action).
In order to register actions as commands and register routes directly within actions, Laravel Actions need to know where your Actions are kept. By default, it will look inside the app/Actions
directory. This new discovery mechanism might interfere with your current architecture. If this is the case, you can tell Laravel Actions were to look for actions using Actions::paths([...])
in a service provider. Alternatively you can disable this altogether via the Actions::dontRegister()
method. (See Registering actions).
- public function updateAttributeWithResolvedInstance($key, $instance)
+ protected function updateAttributeWithResolvedInstance($key, $instance): void
- protected function findAttributeFromParameter($name, $extras = [])
+ protected function findAttributeFromParameter($name, $extras = []): array
- protected function resolveMethodDependencies($instance, $method, $extras = [])
+ protected function resolveMethodDependencies($instance, $method, $extras = []): array
- public function delegateTo($actionClass)
+ public function delegateTo(string $actionClass)
Published by lorisleiva over 4 years ago
⬆️ Add support for Laravel 7 (#35)
🐎 No longer instantiate every listener to check if it's an action (#33)
✨ Add the following new static helpers to run actions (#36)
MyAction::make([/* ... */])
// Equivalent to:
new MyAction([/* ... */]);
MyAction::run([/* ... */])
// Equivalent to:
(new MyAction)->run([/* ... */]);
⚠️ This is a potential breaking change if your application is overriding the run
method. If that's the case make sure to override the handleRun
method instead.
// Previous signature to override.
public function run(array $attributes = [])
// New signature to override.
protected function handleRun(array $attributes = [])
Published by lorisleiva almost 5 years ago
✨ Add support for dependency injection to the following methods: rules()
, messages()
and attributes()
.
This means you can now resolve your Eloquent models or Service classes before even reaching the handle()
method.
This could be helpful, for example, when excluding a model in a unique
rule.
class UpdateTeamProfile extends Action
{
public function rules(Team $team)
{
return [
'name' => ['filled', 'max:255'],
'slug' => [
'filled',
'alpha_dash',
Rule::exists('teams')->ignore($team->id),
],
];
}
public function handle(Team $team)
{
$team->update($this->validated());
return $team;
}
}
Published by lorisleiva almost 5 years ago
🐛 Edit the Bus Dispatcher so that it uses the action itself as a job handler instead of a proxy. This allows the use of properties like public $timeout
directly within the action. (see #28)
Published by lorisleiva almost 5 years ago
__isset
magic method. (#27)Published by lorisleiva almost 5 years ago
prepareForValidation
method (9c99635af7cd8d20a8034bec49e50c107896c818)Published by lorisleiva about 5 years ago
⬆️ Add support for Laravel 6.x
Published by lorisleiva about 5 years ago
⚠️ Middleware registration (breaking changes) In preparation of Laravel 6, the middleware registration changes slightly to follow the same API as the upcoming Job middleware.
// Before.
public function register()
{
$this->middleware('auth');
}
// After.
public function middleware()
{
return ['auth'];
}
✨ Actions are now invokable as objects
// When running an action as an object.
$action = new PublishANewArticle([
'title' => 'My blog post',
'body' => 'Lorem ipsum.',
]);
// You can now run it like this...
$action();
// Which is equivalent to...
$action->run();
Published by lorisleiva about 5 years ago
🚑 Fix namespace typo (#16)
Published by lorisleiva over 5 years ago
🚑 Fix issue #7 by decorating the existing event dispatcher instead of overriding it with a new instance.