Skip to content

Commit

Permalink
Allow for nullable route model bindings
Browse files Browse the repository at this point in the history
  • Loading branch information
lorisleiva committed May 23, 2020
1 parent 1e925c9 commit 17c69bd
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 25 deletions.
44 changes: 24 additions & 20 deletions src/Concerns/ResolvesMethodDependencies.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,49 +41,53 @@ protected function resolveDependency(ReflectionParameter $parameter, $extras = [
return $value;
}

if ($key && is_subclass_of($class->name, UrlRoutable::class)) {
return $this->resolveRouteBinding($class->name, $key, $value, $parameter->allowsNull());
}

if ($class && ! $parameter->allowsNull()) {
return $this->resolveContainerDependency($class->name, $key, $value);
return $this->resolveContainerDependency($class->name, $key);
}

if ($parameter->isDefaultValueAvailable()) {
return $parameter->getDefaultValue();
}
}

protected function resolveContainerDependency($class, $key, $value)
protected function resolveRouteBinding($class, $key, $value, $nullable = false)
{
$instance = app($class);

if ($key && method_exists($instance, 'resolveRouteBinding')) {
$instance = $this->resolveRouteBinding($instance, $key, $value);
}

if ($key) {
$this->updateAttributeWithResolvedInstance($key, $instance);
}

return $instance;
}

protected function resolveRouteBinding($instance, $key, $value)
{
$route = $this->runningAs('controller') ? $this->request->route() : null;
$field = $route && method_exists($route, 'bindingFieldFor') ? $route->bindingFieldFor($key) : null;
$parent = $route && method_exists($route, 'parentOfParameter') ? $route->parentOfParameter($key) : null;

if ($parent && $field && $parent instanceof UrlRoutable) {
if (! $model = $parent->resolveChildRouteBinding($key, $value, $field)) {
throw (new ModelNotFoundException)->setModel(get_class($instance), [$value]);
}
} else if (! $model = $instance->resolveRouteBinding($value, $field)) {
$model = $parent->resolveChildRouteBinding($key, $value, $field);
} else {
$model = $instance->resolveRouteBinding($value, $field);
}

if (! $model && ! $nullable) {
throw (new ModelNotFoundException)->setModel(get_class($instance), [$value]);
}

optional($route)->setParameter($key, $model);
$this->updateAttributeWithResolvedInstance($key, $model);

return $model;
}

protected function resolveContainerDependency($class, $key)
{
$instance = app($class);

if ($key) {
$this->updateAttributeWithResolvedInstance($key, $instance);
}

return $instance;
}

protected function findAttributeFromParameter($name, $extras = []): array
{
$routeAttributes = $this->runningAs('controller') ? $this->getAttributesFromRoute($this->request) : [];
Expand Down
37 changes: 32 additions & 5 deletions tests/ResolvesMethodDependenciesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,7 @@ public function handle(?Dummy $dummy, Request $request = null) {
public function it_resolves_type_hinted_models_using_route_model_binding()
{
$this->loadLaravelMigrations();
$this->createUser([
'name' => 'John Doe',
'email' => '[email protected]',
]);
$this->createUser(['name' => 'John Doe']);

$action = new class(['user' => 1]) extends Action {
public function handle(User $user) {
Expand All @@ -137,7 +134,37 @@ public function handle(User $user) {
$user = $action->run();
$this->assertTrue($user instanceof User);
$this->assertEquals('John Doe', $user->name);
$this->assertEquals('[email protected]', $user->email);
}

/** @test */
public function it_resolves_nullable_type_hinted_models()
{
$this->loadLaravelMigrations();
$this->createUser(['name' => 'John Doe']);

$action = new class(['user' => 1]) extends Action {
public function handle(?User $user) {
return $user;
}
};

$user = $action->run();
$this->assertTrue($user instanceof User);
$this->assertEquals('John Doe', $user->name);
}

/** @test */
public function it_returns_null_when_nullable_type_hinted_models_cannot_be_found()
{
$this->loadLaravelMigrations();

$action = new class(['user' => null]) extends Action {
public function handle(?User $user) {
return $user;
}
};

$this->assertNull($action->run());
}

/** @test */
Expand Down

0 comments on commit 17c69bd

Please sign in to comment.