Skip to content

Commit

Permalink
Merge pull request #6 from kbond/call
Browse files Browse the repository at this point in the history
feat: add dynamic `service_*` filters/functions
  • Loading branch information
kbond authored Feb 16, 2023
2 parents 14163b0 + 52bc2e5 commit ce26f6d
Show file tree
Hide file tree
Showing 10 changed files with 60 additions and 21 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
fixcs:
name: Run php-cs-fixer
needs: sync-with-template
if: (github.event_name == 'push' || github.event_name == 'schedule') && !startsWith(github.ref, 'refs/tags')
if: (github.event_name == 'push' || github.event_name == 'schedule') && !startsWith(github.ref, 'refs/tags') && github.repository_owner == 'zenstruck'
runs-on: ubuntu-latest
steps:
- uses: zenstruck/.github@php-cs-fixer
Expand All @@ -33,7 +33,7 @@ jobs:

sync-with-template:
name: Sync meta files
if: (github.event_name == 'push' || github.event_name == 'schedule') && !startsWith(github.ref, 'refs/tags')
if: (github.event_name == 'push' || github.event_name == 'schedule') && !startsWith(github.ref, 'refs/tags') && github.repository_owner == 'zenstruck'
runs-on: ubuntu-latest
steps:
- uses: zenstruck/.github@sync-with-template
Expand Down
31 changes: 27 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ composer require zenstruck/twig-service-bundle
## Usage

### Service Function

Mark any service you'd like to make available in twig templates with the `AsTwigService`
attribute which requires an _alias_:

Expand All @@ -40,7 +42,7 @@ namespace App\Twig\Service;
// ...
use Zenstruck\Twig\AsTwigService;

#[AsTwigService(alias: 'post-service')]
#[AsTwigService(alias: 'posts')]
class PostService
{
private PostRepository $repo;
Expand All @@ -63,7 +65,15 @@ class PostService
You're now ready to access the service in any twig template:

```twig
{% for post in service('post-service').latestPosts(5) %}
{% for post in service('posts').latestPosts(5) %}
{# ... #}
{% endfor %}
```

There is also a dynamic function. The following is equivalent to above:

```twig
{% for post in service_posts().latestPosts(5) %}
{# ... #}
{% endfor %}
```
Expand All @@ -78,7 +88,7 @@ namespace App\Twig\Service;
// ...
use Zenstruck\Twig\AsTwigService;

#[AsTwigService(alias: 'image-transformer')]
#[AsTwigService(alias: 'image_transformer')]
class ImageTransformer
{
public function __invoke(string $imageUrl, string ...$transformations): string
Expand All @@ -91,5 +101,18 @@ class ImageTransformer
In your template, use the `service` twig filter:

```twig
{{ url|service('image-transformer', 'square-200', 'watermark') }}
{{ url|service('image_transformer', 'square-200', 'watermark') }}
```

There is also a dynamic filter. The following is equivalent to above:

```twig
{{ url|service_image_transformer('square-200', 'watermark') }}
```

Note, the output will be escaped. If your filter returns html that you don't want
escaped, use the `raw` filter:

```twig
{{ url|service_image_transformer('square-200', 'watermark')|raw }}
```
10 changes: 8 additions & 2 deletions src/Service/TwigServiceExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,17 @@ final class TwigServiceExtension extends AbstractExtension
{
public function getFunctions(): array
{
return [new TwigFunction('service', [TwigServiceRuntime::class, 'get'])];
return [
new TwigFunction('service', [TwigServiceRuntime::class, 'get']),
new TwigFunction('service_*', [TwigServiceRuntime::class, 'get']),
];
}

public function getFilters(): array
{
return [new TwigFilter('service', [TwigServiceRuntime::class, 'filter'])];
return [
new TwigFilter('service', [TwigServiceRuntime::class, 'filter']),
new TwigFilter('service_*', [TwigServiceRuntime::class, 'dynamicFilter']),
];
}
}
5 changes: 5 additions & 0 deletions src/Service/TwigServiceRuntime.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,9 @@ public function filter(mixed $value, string $alias, mixed ...$args): mixed

return $service($value, ...$args);
}

public function dynamicFilter(string $alias, mixed $value, mixed ...$args): mixed
{
return $this->filter($value, $alias, ...$args);
}
}
2 changes: 1 addition & 1 deletion tests/Fixture/ServiceA.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
/**
* @author Kevin Bond <kevinbond@gmail.com>
*/
#[AsTwigService('service-a')]
#[AsTwigService('service_a')]
final class ServiceA
{
public string $property = 'prop value';
Expand Down
2 changes: 1 addition & 1 deletion tests/Fixture/ServiceB.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
/**
* @author Kevin Bond <kevinbond@gmail.com>
*/
#[AsTwigService('service-b')]
#[AsTwigService('service_b')]
final class ServiceB
{
}
9 changes: 6 additions & 3 deletions tests/Fixture/templates/template1.html.twig
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
{{ service('service-a').property }}
{{ service('service-a').method(1) }}
{{ service('service-a').method(2) }}
{{ service('service_a').property }}
{{ service('service_a').method(1) }}
{{ service('service_a').method(2) }}
{{ service_service_a().property }}
{{ service_service_a().method(1) }}
{{ service_service_a().method(2) }}
6 changes: 4 additions & 2 deletions tests/Fixture/templates/template3.html.twig
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
{{ 'foo'|service('service-a') }}
{{ 'foo'|service('service-a', 'bar', 'baz') }}
{{ 'foo'|service('service_a') }}
{{ 'foo'|service('service_a', 'bar', 'baz') }}
{{ 'foo'|service_service_a }}
{{ 'foo'|service_service_a('bar', 'baz') }}
2 changes: 1 addition & 1 deletion tests/Fixture/templates/template4.html.twig
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{{ 'foo'|service('service-b') }}
{{ 'foo'|service('service_b') }}
10 changes: 5 additions & 5 deletions tests/IntegrationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public function can_access_service_by_alias(): void
{
$rendered = self::getContainer()->get('twig')->render('template1.html.twig');

$this->assertSame("prop value\nmethod return 1\nmethod return 2\n", $rendered);
$this->assertSame("prop value\nmethod return 1\nmethod return 2\nprop value\nmethod return 1\nmethod return 2\n", $rendered);
}

/**
Expand All @@ -35,7 +35,7 @@ public function can_access_service_by_alias(): void
public function invalid_service_alias(): void
{
$this->expectException(RuntimeError::class);
$this->expectExceptionMessage('Twig service with alias "invalid" is not registered. Registered services: "service-a, service-b"');
$this->expectExceptionMessage('Twig service with alias "invalid" is not registered. Registered services: "service_a, service_b"');

self::getContainer()->get('twig')->render('template2.html.twig');
}
Expand All @@ -47,7 +47,7 @@ public function invokable_service_filter(): void
{
$rendered = self::getContainer()->get('twig')->render('template3.html.twig');

$this->assertSame("foo\nfoo bar baz\n", $rendered);
$this->assertSame("foo\nfoo bar baz\nfoo\nfoo bar baz\n", $rendered);
}

/**
Expand All @@ -56,7 +56,7 @@ public function invokable_service_filter(): void
public function invokable_service_filter_must_be_invokable(): void
{
$this->expectException(RuntimeError::class);
$this->expectExceptionMessage('Twig service "service-b" (Zenstruck\Twig\Tests\Fixture\ServiceB) must be implement "__invoke()" to be used as an invokable service filter.');
$this->expectExceptionMessage('Twig service "service_b" (Zenstruck\Twig\Tests\Fixture\ServiceB) must be implement "__invoke()" to be used as an invokable service filter.');

self::getContainer()->get('twig')->render('template4.html.twig');
}
Expand All @@ -67,7 +67,7 @@ public function invokable_service_filter_must_be_invokable(): void
public function invalid_invokable_service_alias(): void
{
$this->expectException(RuntimeError::class);
$this->expectExceptionMessage('Twig service with alias "invalid" is not registered. Registered services: "service-a, service-b"');
$this->expectExceptionMessage('Twig service with alias "invalid" is not registered. Registered services: "service_a, service_b"');

self::getContainer()->get('twig')->render('template5.html.twig');
}
Expand Down

0 comments on commit ce26f6d

Please sign in to comment.