Skip to content

Commit

Permalink
Fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
HypeMC committed Oct 25, 2024
1 parent 84dfb84 commit e1fcfed
Show file tree
Hide file tree
Showing 2 changed files with 158 additions and 21 deletions.
141 changes: 133 additions & 8 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ The bundle includes built-in support for [Symfony HTTP Cache](https://symfony.co
basic [Varnish](https://varnish-cache.org/) implementation. Each backend is realized by implementing
the [`PurgerInterface`](/src/Purger/PurgerInterface.php).

It also comes with a `void`, which can be used during development when cache purging is not required. The `void` simply
ignores all purge requests, making it ideal for non-production environments. Additionally, an `in-memory` is provided,
designed specifically for testing purposes. The `in-memory` simulates purging actions without interacting with external
cache services, enabling you to verify your purging logic in tests.
It also comes with a `void` purger, which can be used during development when cache purging is not required. The `void`
purger simply ignores all purge requests, making it ideal for non-production environments. Additionally, an `in-memory`
purger is provided, designed specifically for testing purposes. The `in-memory` purger simulates purging actions without
interacting with external cache services, enabling you to verify your purging logic in tests.

For advanced use cases, you can create [custom purgers](/docs/custom-purgers.md). This allows you to integrate with any
custom or third-party HTTP cache backend that fits your project requirements.
Expand Down Expand Up @@ -106,7 +106,17 @@ purgatory:
transport: async
```

Then, run the `messenger:consume` command:
If needed, you can limit the number of purge requests included in each message by setting a `batch_size`:

```yaml
# config/packages/purgatory.yaml
purgatory:
messenger:
transport: async
batch_size: 10
```

To start processing purge requests asynchronously, run the following command:

```shell
bin/console messenger:consume async
Expand All @@ -123,7 +133,9 @@ properties with corresponding routes and route parameters. These subscriptions h
purged based on changes to the entities.

To determine which routes need purging, the bundle relies on **route providers**. These services evaluate the purge
subscriptions and determine the relevant routes and parameters based on the changes detected in the entities.
subscriptions and determine the relevant routes and parameters based on the changes detected in the entities. When
dealing with updates, the route provider returns the same route twice, once with the old parameters and once with the
new parameters.

Using this information, the bundle generates the URLs that need to be purged. It then sends these purge requests to the
configured purger, which clears the cached content for those URLs.
Expand Down Expand Up @@ -158,9 +170,65 @@ class PostController

Here, the `id` property is automatically mapped to the route parameter with the same name.

You can also apply this to a controller class using the `__invoke` method:

```php
use Sofascore\PurgatoryBundle\Attribute\PurgeOn;
use Symfony\Component\Routing\Attribute\Route;
#[Route('/post/{id<\d+>}', name: 'post_details', methods: 'GET')]
#[PurgeOn(Post::class)]
class PostDetailsController
{
public function __invoke(Post $post)
{
}
}
```

In this case, the subscription is added at the class level, making it suitable for single-action controllers.

### Inheritance and Subscriptions

When using inheritance mapping, the bundle automatically creates purge subscriptions for all child entities as well.
This means that purging rules applied to a parent class will also be inherited by its child classes:

```php
use Doctrine\ORM\Mapping as ORM;
#[ORM\MappedSuperclass]
class Animal {}
#[ORM\Entity]
class Cat extends Animal {}
#[ORM\Entity]
class Dog extends Animal {}
```

For example, if you define a purge subscription for the `Animal` entity, it will also apply to `Cat` and `Dog` entities:

```php
use Sofascore\PurgatoryBundle\Attribute\PurgeOn;
use Symfony\Component\Routing\Attribute\Route;
class AnimalController
{
#[Route('/animal/{id<\d+>}', name: 'animal_details', methods: 'GET')]
#[PurgeOn(Animal::class)]
public function detailsAction(Animal $animal)
{
}
}
```

In this case, changes to `Cat`, `Dog`, or any future subclasses of `Animal` will trigger the purging of the
corresponding route. This allows you to define common purging behavior for all related entities by setting it up once on
the parent class.

### Explicit Mapping of Route Parameters

If the parameter names differ, you can explicitly map them:
If the parameter names differ, you have to explicitly map them:

```php
#[Route('/post/{postId<\d+>}', name: 'post_details', methods: 'GET')]
Expand Down Expand Up @@ -220,6 +288,43 @@ class Post

In this example, the purge will only occur if the `title` or `author` properties change.

### Targeting `OneTo*` Relations

For `OneToMany` or `OneToOne` relations, the bundle automatically creates inverse subscriptions for related entities.
This means that changes in the related entity will also trigger a purge for the primary entity's routes.

For example:

```php
#[Route('/post/{id<\d+>}', name: 'post_details', methods: 'GET')]
#[PurgeOn(Post::class, target: 'author')]
public function detailsAction(Post $post)
{
}
```

In this case, if any property of the `Author` entity changes, the post details page will be purged. This automatic
subscription simplifies the purging logic by handling relationships between entities without additional manual
configuration.

### Targeting Embeddables

When targeting an embeddable, the bundle subscribes to all properties of the embeddable by default. This is useful when
the embeddable encapsulates multiple related fields that should trigger purging as a group.

For example:

```php
#[Route('/author/{id<\d+>}', name: 'author_details', methods: 'GET')]
#[PurgeOn(Author::class, target: 'address')]
public function detailsAction(Author $author)
{
}
```

Here, the `address` target subscribes to all properties within the `Address` embeddable class. If any property within
`Address` changes (such as `street`, `city`, or `postalCode`), the author details page will be purged.

### Using Serialization Groups

You can also specify which Symfony
Expand All @@ -234,7 +339,27 @@ public function detailsAction(Post $post)
}
```

Now, the purge will occur for all properties that are part of the `common` serialization group.
In this case, the purge will occur for all properties that are part of the `common` serialization group or are listed as
`#[TargetedProperties]` on a method with that group:

```php
use Doctrine\ORM\Mapping as ORM;
use Sofascore\PurgatoryBundle\Attribute\TargetedProperties;
use Symfony\Component\Serializer\Attribute\Groups;
#[ORM\Entity]
class Post
{
// ...
#[Groups('common')]
#[TargetedProperties('title', 'author')]
public function getTitleAndAuthor(): string
{
return $this->title.', '.$this->author->getFullName();
}
}
```

### Adding Conditional Logic with Expression Language

Expand Down
38 changes: 25 additions & 13 deletions docs/complex-route-params.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ values to create flexible and powerful purge rules.

## Using Nested Properties

You can access nested properties of an entity to define route parameters:
You can access nested properties of an entity to define route parameters by
using [Symfony's Property Access](https://symfony.com/doc/current/components/property_access.html) syntax:

```php
#[Route('/author/{id<\d+>}', name: 'author_details', methods: 'GET')]
Expand Down Expand Up @@ -46,12 +47,23 @@ individual post. This ensures that each item in the collection has its correspon

When working with multiple collections, the bundle generates
a [Cartesian product](https://en.wikipedia.org/wiki/Cartesian_product) of URLs, ensuring that all combinations of
elements within the collections are purged.
elements within the collections are purged:

```php
#[Route('/posts/{tag}/{commentId<\d+>}', name: 'posts_list', methods: 'GET')]
#[PurgeOn(Post::class, routeParams: ['tag' => 'tags[*].id', 'commentId' => 'comments[*].id'])]
public function listAction(string $tag, Comment $comment)
{
}
```

In this example, URLs are generated for all combinations of `tag` and `commentId` based on the elements in the `tags`
and `comments` collections. This ensures that each unique combination within the collections is accounted for.

## Using Non-Property Values as Route Parameters

In addition to mapping entity properties to route parameters, you can use various other value types. This flexibility
allows you to customize routes based on raw values, enums, or even dynamic values provided by services.
allows you to customize routes based on raw values, backed enums, or even dynamic values provided by services.

### Using Raw Values

Expand All @@ -60,9 +72,9 @@ You can specify raw values directly in the route parameters:
```php
use Sofascore\PurgatoryBundle\Attribute\RouteParamValue\RawValues;

#[Route('/post/{type}', name: 'post_details', methods: 'GET')]
#[Route('/posts/{type}', name: 'posts_list', methods: 'GET')]
#[PurgeOn(Post::class, routeParams: ['type' => new RawValues('foo')])]
public function detailsAction(Post $post)
public function listAction(string $type)
{
}
```
Expand All @@ -71,14 +83,14 @@ In this example, the route parameter `type` is explicitly set to the value `foo`

### Using Enum Values

If you have a predefined set of values in an enum, you can map route parameters to those enum values:
If you have a predefined set of values in a backed enum, you can map route parameters to those enum values:

```php
use Sofascore\PurgatoryBundle\Attribute\RouteParamValue\EnumValues;

#[Route('/post/{type}', name: 'post_details', methods: 'GET')]
#[Route('/posts/{type}', name: 'posts_list', methods: 'GET')]
#[PurgeOn(Post::class, routeParams: ['type' => new EnumValues(TypeEnum::class)])]
public function detailsAction(Post $post)
public function listAction(string $type)
{
}
```
Expand All @@ -94,12 +106,12 @@ use Sofascore\PurgatoryBundle\Attribute\RouteParamValue\CompoundValues;
use Sofascore\PurgatoryBundle\Attribute\RouteParamValue\EnumValues;
use Sofascore\PurgatoryBundle\Attribute\RouteParamValue\RawValues;

#[Route('/post/{lang}', name: 'post_details', methods: 'GET')]
#[Route('/posts/{lang}', name: 'posts_list', methods: 'GET')]
#[PurgeOn(Post::class, routeParams: ['lang' => new CompoundValues(
new EnumValues(LanguageCodes::class),
new RawValues('XK'), // Kosovo code
)])]
public function detailsAction(Post $post)
public function listAction(string $lang)
{
}
```
Expand All @@ -115,9 +127,9 @@ route parameters that depend on context or runtime information:
```php
use Sofascore\PurgatoryBundle\Attribute\RouteParamValue\DynamicValues;

#[Route('/post/{type}', name: 'post_details', methods: 'GET')]
#[Route('/posts/{type}', name: 'posts_list', methods: 'GET')]
#[PurgeOn(Post::class, routeParams: ['type' => new DynamicValues('my_service')])]
public function detailsAction(Post $post)
public function listAction(string $lang)
{
}
```
Expand All @@ -140,7 +152,7 @@ use Sofascore\PurgatoryBundle\Attribute\AsRouteParamService;
#[AsRouteParamService('my_service')]
class MyService
{
public function __invoke()
public function __invoke(Post $post)
{
// Return the desired value for the route parameter
}
Expand Down

0 comments on commit e1fcfed

Please sign in to comment.