Skip to content

Commit

Permalink
Merge pull request #141 from michaelhrivnak/add-with-trashed-attribute
Browse files Browse the repository at this point in the history
Added WithTrashed attribute
  • Loading branch information
freekmurze authored Apr 24, 2024
2 parents 8831b1e + f37b602 commit f201355
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 4 deletions.
40 changes: 40 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,46 @@ Route::get('my-default-route/{param?}/{param2?}/{param3?}', [MyController::class
Route::get('my-override-route/{param?}', [MyController::class, 'myOverrideMethod'])->setDefaults(['param', 'method-default']);
```

### With Trashed

You can use the `WithTrashed` annotation on a class or method to enable WithTrashed bindings to the model.
You can explicitly override the behaviour using `WithTrashed(false)` if it is applied at the class level

```php
use Spatie\RouteAttributes\Attributes\Get;
use Spatie\RouteAttributes\Attributes\Post;
use Spatie\RouteAttributes\Attributes\WithTrashed;

#[WithTrashed]
class MyController extends Controller
{
#[Get('my-get-route/{param}')]
#[WithTrashed]
public function myGetMethod($param)
{
}

#[Post('my-post-route/{param}')]
#[WithTrashed(false)]
public function myPostMethod($param)
{
}

#[Get('my-default-route/{param}')]
public function myDefaultMethod($param)
{
}
}
```
These annotations will automatically register these routes:

```php
Route::get('my-get-route/{param}', [MyController::class, 'myGetMethod'])->WithTrashed();
Route::post('my-post-route/{param}', [MyController::class, 'myPostMethod'])->withTrashed(false);
Route::get('my-default-route/{param}', [MyController::class, 'myDefaultMethod'])->withTrashed();
```


## Testing

``` bash
Expand Down
16 changes: 16 additions & 0 deletions src/Attributes/WithTrashed.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

namespace Spatie\RouteAttributes\Attributes;

use Attribute;

#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_CLASS )]
class WithTrashed implements RouteAttribute
{
public bool $withTrashed;

public function __construct(bool $withTrashed = true)
{
$this->withTrashed = $withTrashed;
}
}
14 changes: 14 additions & 0 deletions src/ClassRouteAttributes.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use Spatie\RouteAttributes\Attributes\RouteAttribute;
use Spatie\RouteAttributes\Attributes\ScopeBindings;
use Spatie\RouteAttributes\Attributes\Where;
use Spatie\RouteAttributes\Attributes\WithTrashed;

class ClassRouteAttributes
{
Expand Down Expand Up @@ -236,6 +237,19 @@ public function defaults(): array
return $defaults;
}

/**
* @psalm-suppress NoInterfaceProperties
*/
public function withTrashed() : bool
{
/** @var ?WithTrashed $attribute */
if (! $attribute = $this->getAttribute(WithTrashed::class)) {
return false;
}

return $attribute->withTrashed;
}

protected function getAttribute(string $attributeClass): ?RouteAttribute
{
$attributes = $this->class->getAttributes($attributeClass, \ReflectionAttribute::IS_INSTANCEOF);
Expand Down
31 changes: 29 additions & 2 deletions src/RouteRegistrar.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use Spatie\RouteAttributes\Attributes\RouteAttribute;
use Spatie\RouteAttributes\Attributes\ScopeBindings;
use Spatie\RouteAttributes\Attributes\WhereAttribute;
use Spatie\RouteAttributes\Attributes\WithTrashed;
use SplFileInfo;
use Symfony\Component\Finder\Finder;
use Throwable;
Expand Down Expand Up @@ -139,7 +140,7 @@ protected function registerResource(ReflectionClass $class, ClassRouteAttributes
protected function registerRoutes(ReflectionClass $class, ClassRouteAttributes $classRouteAttributes): void
{
foreach ($class->getMethods() as $method) {
list($attributes, $wheresAttributes, $defaultAttributes, $fallbackAttributes, $scopeBindingsAttribute) = $this->getAttributesForTheMethod($method);
list($attributes, $wheresAttributes, $defaultAttributes, $fallbackAttributes, $scopeBindingsAttribute, $withTrashedAttribute) = $this->getAttributesForTheMethod($method);


foreach ($attributes as $attribute) {
Expand Down Expand Up @@ -171,6 +172,8 @@ protected function registerRoutes(ReflectionClass $class, ClassRouteAttributes $

$this->addMiddlewareToRoute($classRouteAttributes, $attributeClass, $route);

$this->setWithTrashedIfAvailable($classRouteAttributes, $withTrashedAttribute, $route);


if (count($fallbackAttributes) > 0) {
$route->fallback();
Expand Down Expand Up @@ -209,8 +212,9 @@ public function getAttributesForTheMethod(\ReflectionMethod $method): array
$defaultAttributes = $method->getAttributes(Defaults::class, ReflectionAttribute::IS_INSTANCEOF);
$fallbackAttributes = $method->getAttributes(Fallback::class, ReflectionAttribute::IS_INSTANCEOF);
$scopeBindingsAttribute = $method->getAttributes(ScopeBindings::class, ReflectionAttribute::IS_INSTANCEOF)[0] ?? null;
$withTrashedAttribute = $method->getAttributes(WithTrashed::class, ReflectionAttribute::IS_INSTANCEOF)[0] ?? null;

return [$attributes, $wheresAttributes, $defaultAttributes, $fallbackAttributes, $scopeBindingsAttribute];
return [$attributes, $wheresAttributes, $defaultAttributes, $fallbackAttributes, $scopeBindingsAttribute, $withTrashedAttribute];
}

/**
Expand Down Expand Up @@ -277,6 +281,29 @@ public function setDefaultsIfAvailable(ClassRouteAttributes $classRouteAttribute
}
}

/**
* @param ClassRouteAttributes $classRouteAttributes
* @param ReflectionAttribute|null $withTrashedAttribute
* @param \Illuminate\Routing\Route $route
* @return void
*/
public function setWithTrashedIfAvailable(ClassRouteAttributes $classRouteAttributes, ?ReflectionAttribute $withTrashedAttribute, \Illuminate\Routing\Route $route): void
{
$withTrashed = $classRouteAttributes->withTrashed();


if($withTrashedAttribute !== null)
{
/** @var WithTrashed $instance */
$instance = $withTrashedAttribute->newInstance();
$route->withTrashed($instance->withTrashed);
}
else
{
$route->withTrashed($withTrashed);
}
}

/**
* @param ReflectionClass $class
* @param ClassRouteAttributes $classRouteAttributes
Expand Down
42 changes: 42 additions & 0 deletions tests/AttributeTests/WithTrashedAttributeTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

namespace AttributeTests;

use Spatie\RouteAttributes\Tests\TestCase;
use Spatie\RouteAttributes\Tests\TestClasses\Controllers\WithTrashedTestController;

class WithTrashedAttributeTest extends TestCase
{
/** @test */
public function it_can_apply_with_trashed_on_a_controller(): void
{
$this->routeRegistrar->registerClass(WithTrashedTestController::class);

$this
->assertRegisteredRoutesCount(3)
->assertRouteRegistered(
WithTrashedTestController::class,
controllerMethod: 'withTrashedRoute',
httpMethods: 'get',
uri: 'with-trashed-test-method/{param}',
withTrashed: true,

)
->assertRouteRegistered(
WithTrashedTestController::class,
controllerMethod: 'withoutTrashedRoute',
httpMethods: 'get',
uri: 'with-trashed-test-method-2/{param}',
withTrashed: false,
)
// registered through
->assertRouteRegistered(
WithTrashedTestController::class,
controllerMethod: 'noWithTrashedAttributeRoute',
httpMethods: 'get',
uri: 'with-trashed-test-method-3/{param}',
withTrashed: true,
)
;
}
}
9 changes: 7 additions & 2 deletions tests/TestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,15 @@ public function assertRouteRegistered(
?bool $isFallback = false,
?bool $enforcesScopedBindings = false,
?bool $preventsScopedBindings = false,
?array $defaults = []
?array $defaults = [],
?bool $withTrashed = false,
): self {
if (! is_array($middleware)) {
$middleware = Arr::wrap($middleware);
}

$routeRegistered = collect($this->getRouteCollection()->getRoutes())
->contains(function (Route $route) use ($name, $middleware, $controllerMethod, $controller, $uri, $httpMethods, $domain, $wheres, $isFallback, $enforcesScopedBindings, $preventsScopedBindings, $defaults) {
->contains(function (Route $route) use ($name, $middleware, $controllerMethod, $controller, $uri, $httpMethods, $domain, $wheres, $isFallback, $enforcesScopedBindings, $preventsScopedBindings, $defaults, $withTrashed) {
foreach (Arr::wrap($httpMethods) as $httpMethod) {
if (! in_array(strtoupper($httpMethod), $route->methods)) {
return false;
Expand Down Expand Up @@ -111,6 +112,10 @@ public function assertRouteRegistered(
return false;
}

if($route->allowsTrashedBindings() !== $withTrashed){
return false;
}

return true;
});

Expand Down
21 changes: 21 additions & 0 deletions tests/TestClasses/Controllers/WithTrashedTestController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

namespace Spatie\RouteAttributes\Tests\TestClasses\Controllers;

use Spatie\RouteAttributes\Attributes\Get;
use Spatie\RouteAttributes\Attributes\WithTrashed;

#[WithTrashed]
class WithTrashedTestController
{
#[Get('with-trashed-test-method/{param}')]
#[WithTrashed]
public function withTrashedRoute() {}

#[Get('with-trashed-test-method-2/{param}')]
#[WithTrashed(false)]
public function withoutTrashedRoute() {}

#[Get('with-trashed-test-method-3/{param}')]
public function noWithTrashedAttributeRoute() {}
}

0 comments on commit f201355

Please sign in to comment.