I have an issue getting Symfony to play nicely with a tag-aware adapter for redis
Unfortunately for me, Symfony 5.2 includes this feature, but as we're not switching to a non-lts version that's kind of out of the question. I have tried checking out the configuration, but it does not quite work for me.
Here's my current setup:
# cache.yaml
framework:
cache:
prefix_seed: !php/const App\Kernel::APP_VERSION
app: cache.adapter.redis_tag_aware
redis.cache_app:
class: Redis
factory: ['Symfony\Component\Cache\Adapter\RedisAdapter', 'createConnection']
arguments:
- '%env(REDIS_DNS)%'
cache.adapter.redis_tag_aware:
class: Symfony\Component\Cache\Adapter\RedisTagAwareAdapter
arguments:
$redisClient: '#redis.cache_app'
$marshaller: '#?cache.default_marshaller'
calls:
- ['setLogger', ['#?logger']]
tags:
- { name: cache.pool, provider: cache.default_redis_provider, clearer: cache.default_clearer, reset: reset }
- { name: monolog.logger, channel: cache }
But it screams about argument 0 not existing via some CompilerPass.
Is it not possible to use the App cache as a tagged cache? I suppose I could create a separate pool and maybe use that, but it seems like a weird choice.
Okay so obviously this is a config issue.
The following will work
# services.yaml
redis.cache_app:
class: Redis
factory: ['Symfony\Component\Cache\Adapter\RedisAdapter', 'createConnection']
arguments:
- '%env(REDIS_DNS)%'
cache.app.redis_tag_aware:
class: Symfony\Component\Cache\Adapter\RedisTagAwareAdapter
arguments:
- '#redis.cache_app'
- ''
- 0
- '#?cache.default_marshaller'
calls:
- ['setLogger', ['#?logger']]
tags:
- { name: cache.pool, provider: redis.cache_app, clearer: cache.default_clearer, reset: reset }
- { name: monolog.logger, channel: cache }
# cache.yaml
framework:
cache:
prefix_seed: !php/const App\Kernel::APP_VERSION
app: cache.app.redis_tag_aware
Related
I need to have multiple bus in my application written on Symfony. To do so I'm using messenger bundle.
So I need to have:
external_events_bus - which receiving messages from external systems, which using sqs transport
application_events_bus - for application events (using database driver for now)
domain_events_bus - for domain events (using database driver for now)
command_bus - for commands and queries (CQRS) (currently sync)
so in my messenger.yaml I have:
framework:
messenger:
default_bus: command.bus
buses:
command.bus: ~
domain_event.bus: ~
application_event.bus: ~
external_event.bus: ~
transports:
command_bus: '%env(COMMAND_BUS_DSN)%'
internal_event_bus: '%env(INTERNAL_EVENT_BUS_DSN)%'
external_event_bus: '%(EXTERNAL_EVENT_BUS_DSN)%'
routing:
'App\Application\CommandBus\Command': command_bus
'App\Domain\EventBus\DomainEvent': internal_event_bus
'App\Application\EventBus\ApplicationEvent': internal_event_bus
'App\Infrastructure\ExternalEventBus\ExternalEvent': external_event_bus
and in my services.yaml
services:
_defaults:
autowire: true
autoconfigure: true subscribers, etc.
public: false
_instanceof:
# use tags to avoid coupling handler classes to Messenger's interface
App\Application\CommandBus\CommandHandler:
tags: [ { name: messenger.message_handler, bus: command.bus } ]
App\Interfaces\ExternalEventBus\ExternalEventHandler:
tags: [ { name: messenger.message_handler, bus: external_event.bus } ]
App\Domain\EventBus\DomainEventHandler:
tags: [ { name: messenger.message_handler, bus: domain_event.bus } ]
App\Application\EventBus\ApplicationEventHandler:
tags: [ { name: messenger.message_handler, bus: application_event.bus } ]
... // some other services here
App\Application\CommandBus\CommandBus:
class: App\Infrastructure\CommandBus\CommandBus
arguments: [ "#command.bus" ]
App\Domain\EventBus\DomainEventBus:
class: App\Infrastructure\DomainEventBus\DomainEventBus
arguments: [ "#domain_event.bus" ]
App\Application\EventBus\ApplicationEventBus:
class: App\Infrastructure\ApplicationEventBus\ApplicationEventBus
arguments: [ "#application_event.bus" ]
App\Infrastructure\ExternalEventBus\ExternalEventBus:
class: App\Infrastructure\ExternalEventBus\ExternalEventBus
arguments: [ "#external_event.bus" ]
Want to clarify before I had only command bus and external bus and all was fine, but after I added domain and application bus, somethinkg went wrong.
When in tests I'm using ExternalEventBus, to test if external event handled correctly, like this:
$this->eventBus = self::$container->get(PlatformEventBus::class);
$this->eventBus->dispatch(new SomeExternalEvent());
I'm getting error like
Symfony\Component\Messenger\Exception\NoHandlerForMessageException: No handler for message "SomeExternalEvent".
but when I'm running bin/console debug:messenger for both dev and test env, I can see correct mapping between all events and their handlers.
But when I'm debugging it can see that HandlersLocator::getHandlers() for that SomeExternalEvent for some reason returning list of handlers related to command bus instead of external event bus (maybe because command bus set as a default bus)
I know it's a bit hard to explaing and show topic, but I spend already whole day truing to find what is wrong with it. Any help appreciated, thank you!!!
Sorry for any kind of typos, I'm a bit change name of classes for this example and may did some typos
okay, I figured it out, messenger using autowiryng when you injecting MessageBusInterface depends on variable name, so in case of external event bus it should be $externalEventBus and same for other buses. But I do not understand how it worked before, as I mentioned I have command and external bus for a while and it stop working only when I add more buses...
I want to use custom namespace in our RedisAdapter to cache in our Symfony4 app. However, when i want to set arguments like this in our services.yaml;
cache.adapter.redis:
class: Symfony\Component\Cache\Adapter\RedisAdapter
arguments:
- '#Redis'
- 'app'
I see this error message:
Symfony\Component\Cache\Traits\RedisTrait::init() expects parameter 1 to be Redis, RedisArray, RedisCluster or Predis\ClientInterface, string given.
By the way, our cache config(config/packages/cache.yaml) is simple like below. So, how can I set namespace directly from any config?
cache:
app: cache.adapter.redis
default_redis_provider: 'redis://%env(REDIS_HOST)%:%env(REDIS_PORT)%'
I solved it with this config:
app.cache.adapter.redis:
parent: 'cache.adapter.redis'
public: true
autowire: true
autoconfigure: false
tags:
- {name: 'cache.pool', namespace: 'app'}
If you need the namespace to be interoperable with a third-party app,
you can take control over auto-generation by setting the namespace attribute of the cache.pool service tag.
For example, you can override the service definition of the adapter:
# config/services.yaml
services:
app.cache.adapter.redis:
parent: 'cache.adapter.redis'
tags:
- { name: 'cache.pool', namespace: 'my_custom_namespace' }
more details here: https://github.com/symfony/symfony-docs/pull/12527
I have the following monolog handler definitions:
# config_prod.yml
app_generic:
type: rotating_file
max_files: 15
path: "%param.app_logging_config.log_generic_file%"
level: info
channels: [app]
app_api:
max_files: 15
path: "%param.app_logging_config.log_api_file%"
level: info
channels: [app]
level: info
app_response:
max_files: 15
path: "%param.app_logging_config.log_response_file%"
channels: [app]
level: info
And in service.yml, my intention is to inject monolog (#logger) with an array of the above defined handlers.
#service.yml
app.app_logger:
class: AppBundle\Classes\AppLogger
arguments: ['#logger': ['#app_generic', '#app_api', '#app_response']]
calls:
- [init, ['%app_logging_config%']
tags:
- { name: monolog.logger, channel: app }
How does one pass arguments to an injected argument?
Update:
Re-reading the description, I was going for this approach, by just tagging on the service definition:
app.logger:
arguments: ['#logger']
tags:
- { name: monolog.logger, channel: app }
channels: ['app']
Or even ( if I understood correctly), adding a channels: ['app'] key and just having this in service argument:
app.logger:
arguments: ['#monolog.logger.app']
I have not been able to use ( or see via dump ) the handlers defined in config_prod.yml. I have placed these at top because of other "fingers_crossed" handlers I thought may interfere.
I woud like to know, why neither of above (documented) approaches seem to work?
Handlers in
monolog:
handlers:
handler1: ...
handler2: ...
are automatically injected in #logger service.
It looks like you need new custom logger. Please read about The DependencyInjection Component
Create dependencies
services:
app_generic:
....
app_api:
....
app_response:
....
Create custom_logger service
custom_logger:
class: Monolog\Logger
arguments: ["my logger", ["#app_generic", "#app_api", "#app_response"]
Inject you custom logger in you service
app.app_logger:
class: AppBundle\Classes\AppLogger
arguments: ['#custom_logger']
calls:
- [init, ['%app_logging_config%']
I have a concern with the following service in my project:
app.security.guardAuthenticatorLoginPassword:
class: AppBundle\Security\LoginPasswordAuthenticator
arguments: ["#router"]
app.jwt_token_authenticator:
class: AppBundle\Security\JwtAuthenticator
arguments: ['#doctrine.orm.entity_manager', '#lexik_jwt_authentication.encoder']
I feel that whatever I do it is not recognized by my program ..
I have been looking for a few hours already but I do not understand why it does not work. While I have both my LoginPasswordAuthenticator and JwtAuthenticator classes in the specified path ..
Thank you in advance for your help
Here is some potentials issues:
_ Clear the cache
_ Check if you didn't forget a 'use' for your differents classes
_ Give to your services a name (and why not an alias) and use it when you call your service:
app.security.guardAuthenticatorLoginPassword:
class: AppBundle\Security\LoginPasswordAuthenticator
arguments: ["#router"]
tags:
- { name: login.password.authenticator, alias: login.auth }
app.jwt_token_authenticator:
class: AppBundle\Security\JwtAuthenticator
arguments:['#doctrine.orm.entity_manager','#lexik_jwt_authentication.encoder']
tags:
- { name: security.authenticator, alias: security.auth }
I'm trying to set up AWS S3/Cloudfront to work with liipimaginebundle in Symfony, but I really have no idea what I'm doing.
So far I have tried the following documented here http://symfony.com/doc/current/bundles/LiipImagineBundle/cache-resolver/aws_s3.html:
Installed aws-sdk-php:
"require": {
"aws/aws-sdk-php": "^3.28",
}
Set up my parameters (with the correct values not this dummy data):
amazon.s3.key: "your-aws-key"
amazon.s3.secret: "your-aws-secret"
amazon.s3.bucket: "your-bucket.example.com"
amazon.s3.region: "your-bucket-region"
Set up a resolver (although I'm not sure what that even means).
"%amazon.s3.cache_bucket%" is in the documentation but the parameter doesn't exist so I used "%amazon.s3.bucket%" instead:
liip_imagine:
cache: profile_photos
resolvers:
profile_photos:
aws_s3:
client_config:
credentials:
key: "%amazon.s3.key%"
secret: "%amazon.s3.secret%"
region: "%amazon.s3.region%"
bucket: "%amazon.s3.bucket%"
get_options:
Scheme: https
put_options:
CacheControl: "max-age=86400"
Added these lines to create the services:
services:
acme.amazon_s3:
class: Aws\S3\S3Client
factory: Aws\S3\S3Client
arguments:
-
credentials: { key: "%amazon.s3.key%", secret: "%amazon.s3.secret%" }
region: "%amazon.s3.region%"
acme.imagine.cache.resolver.amazon_s3:
class: Liip\ImagineBundle\Imagine\Cache\Resolver\AwsS3Resolver
arguments:
- "#acme.amazon_s3"
- "%amazon.s3.bucket%"
tags:
- { name: "liip_imagine.cache.resolver", resolver: "amazon_s3" }
I'm currently getting this error when I run php bin/console server:run:
PHP Fatal error: Uncaught Symfony\Component\Debug\Exception\UndefinedFunctionException: Attempted to call function "S3Client" from namespace "Aws\S3". in /var/www/swing-polls/var/cache/dev/appDevDebugProjectContainer.php:360
I've tried half a dozen other configs/tutorials to no avail. If someone can point me in the right direction I'd be incredibly grateful.
Using the code provided at Simple S3 Symfony Service with a few tweaks, I've been able to get my images to upload to my s3 bucket, but I just don't know how to get liipimaginebundle work with them.
In vendor/liip/imagine-bundle/DependencyInjection/Compiler/ResolversCompilerPass.php you can see the CompilerPass is getting the value from "resolver" attribute of the tag and is using it to create a Reference object. This means the resolver should contain the id of a service.
Try replacing
tags:
- { name: "liip_imagine.cache.resolver", resolver: "amazon_s3" }
with
tags:
- { name: "liip_imagine.cache.resolver", resolver: "acme.amazon_s3" }