Configuring which Redis adapter to use in Symfony Cache - php

I want to make use of Predis\Client instead of \Redis for all the Redis connections.
The Symfony docs on cache adapters describe that you can give additional options to the createConnection method.
However, this is all autowired in the service container. The only thing I'm declaring is that I want to use Redis for caching:
framework:
cache:
app: cache.adapter.redis
default_redis_provider: '%redis_dsn%'
Is there any way I can configure the default options for the RedisAdapter? Or is there another way that I can set Symfony always to use Predis\Client for Redis?
Configuring the DSN with ?class=\Predis\Client works, is this the optimal solution?

There's nothing wrong with adding additional options to the DSN. Being able to configure your provider with just a string is why it exists. However you can define a custom provider service and use whatever configuration you'd like.
From https://symfony.com/doc/current/cache.html#custom-provider-options:
# config/packages/cache.yaml
framework:
cache:
pools:
cache.my_redis:
adapter: cache.adapter.redis
provider: app.my_custom_redis_provider
services:
app.my_custom_redis_provider:
class: \Redis
factory: ['Symfony\Component\Cache\Adapter\RedisAdapter', 'createConnection']
arguments:
- 'redis://localhost'
- { retry_interval: 2, timeout: 10 }
In your case you'd change the class to Client\Predis and change the applicable settings.

Related

How do I switch between different databases using an application Symfony 4 with API Platform?

I am structuring a Symfony 4 application which is also using API Platform. The problem is that we have a demand that a User will have to connect to its own database. So each time it logs in to a centralized domain (just for access purposes), the application will have to connect him to his own database.
I've done some research, and found out that the closest thing specified in Symfony 4 docs is the Multiple Entity Managers and Connections.
The problem here is that although it shows how to create multiple configurations for different database connections, it just specifies how to create them for a specific Entity Manager, or how to get stuff from another Entity Manager inside a Symfony Controller.
In my case, we don't have any Controllers. Instead, there is an API with a couple of services endpoints which connect to the database to manage resources though HTTP requests. Currently, we are using always the default database connection, which gets the configuration from the .env variable.
I know that will have to store this database configuration information in a session (or anything similar) or verify which database is the right one for the given user at each API request. But I'm not so sure what's the best way to deal with this problem.
Also, I thought of creating a listener to the onKernelRequest event, as described in this thread
Any thoughts or ideas how should I proceed with this?
EDIT
This is the packages/doctrine.yaml file. Everything is configured for default.
parameters:
# Adds a fallback DATABASE_URL if the env var is not set.
# This allows you to run cache:warmup even if your
# environment variables are not available yet.
# You should not need to change this value.
env(DATABASE_URL): ''
doctrine:
dbal:
# configure these for your database server
driver: 'pdo_mysql'
server_version: '5.7'
charset: utf8mb4
default_table_options:
charset: utf8mb4
collate: utf8mb4_unicode_ci
url: '%env(resolve:DATABASE_URL)%'
orm:
auto_generate_proxy_classes: true
naming_strategy: doctrine.orm.naming_strategy.underscore
auto_mapping: true
mappings:
App:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Entity'
prefix: 'App\Fst\Entity'
alias: App
And for the .env file:
DATABASE_URL=mysql://db_user:db_password#127.0.0.1:3306/db_name
which is overrided in the .env.local file.
Also, services.yaml has default configuration, with autowiring enabled.

how to inject "memcache" to service.yml?

I installed memcache lib and added it to
framework:
session:
handler_id: session.handler.memcache
but when I trying to use it I get this error
[Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException]
You have requested a non-existent service "session.handler.memcache".
You want to use memcache or memcached?
These are two different extensions, so be aware of that.
And I suggest to use memcached, memcache is dead.
Serivce session.handler.memcache is not defined, so you have to define one implementing SessionHandlerInterface, in your case MemcacheSessionHandler.
First, we need to define memcache instance as a service, so we can pass it to MemcacheSessionHandler constructor:
memcache:
class: \Memcache
calls:
- [ addServer, [ %host_parameter%, %port_parameter% ]]
Then, your session handler:
session.handler.memcache:
class: Symfony\Component\HttpFoundation\Session\Storage\Handler\MemcacheSessionHandler
arguments: [#memcache]
You can also use a bundle like cache/adapter-bundle to register a PSR-6 compatible service (or even a symfony cache component, introduced in 3.1) and use Psr6SessionHandler.
If you want to use memcached, it's almost the same configuration-wise.
Symfony has it's own component: https://symfony.com/doc/current/components/cache.html
You have to configure it first in your /config/packages/framework.yaml:
framework:
cache:
pools:
memcached_service:
adapter: cache.adapter.memcached
public: true
provider: 'memcached://memcached:11211'
Now you can inject your Memcached service wherever you want (services.yaml):
App\Service\SomeService:
arguments:
- "#memcached_service"

Symfony 3.1 PSR-6 Caching Settings

Config.yml:
cache:
app: cache.adapter.doctrine
system: cache.adapter.doctrine
default_doctrine_provider: ~
default_psr6_provider: ~
default_redis_provider: "redis://localhost:6379"
Symfony 3.1 support doctrine cache, but you do not have enough documentation.
Cache Component: http://symfony.com/doc/current/components/cache.html
Supported drives: http://symfony.com/doc/current/components/cache/cache_pools.html
Symfony Integration: http://symfony.com/blog/new-in-symfony-3-1-cache-component
default_doctrine_provider: ? What do I enter as Provider
You can pass to default_doctrine_provider either a Redis connection DSN (for example "redis://127.0.0.1:6379") or ID of a service which implements Symfony\Component\Cache\Adapter\AdapterInterface
You can have a look at already implemented adapters here
The provider basically is the original doctrine_cache provider you configured. Let's say you use the DoctrineCacheBundle and your provider name is my_apc_cache that means the container has the following service:
$myCache = $this->container->get('doctrine_cache.providers.my_apc_cache');
You could also define an alias, then it is even easier.
Take a look at the example at: https://symfony.com/doc/current/bundles/DoctrineCacheBundle/usage.html#service-aliases

logging in symfony 2.3

I am trying to write my own messages to the log in Symfony 2.3, from anywhere, and not just the Controller (which I realize you can just do a "$this->get('logger')".
I've seen that in Symfony 1 you can use sfContext, but that class no longer seems to be a viable choice in 2.3.
Any help is appreciated.
Symfony2 has Service-oriented architecture (http://en.wikipedia.org/wiki/Service-oriented_architecture) and logger is one of service (by default Monolog). In controller you have access to service via $this->get('service_name'). Here is more info about service container: http://symfony.com/doc/current/book/service_container.html#what-is-a-service-container. If you wanna use logger in another service you have to define service and inject logger service. Example:
# section with defined service in your config.yml file (by default in config.yml)
services:
# your service name
my_service:
# your class name
class: Fully\Qualified\Loader\Class\Name
# arguments passed to service constructor. In this case #logger
arguments: ["#logger"]
# tags, info: http://symfony.com/doc/current/components/dependency_injection/tags.html
tags:
- { name: monolog.logger, channel: acme }
Additionally you should familiarize with dependency injection docs: http://symfony.com/doc/current/components/dependency_injection/index.html
I hope that helped. If not, please let me know where exactly you want to use logger.

Symfony 2.1 - Switch Monolog channel in controller

I want to log into a different file than the usual dev.log or prod.log
I know that this can be done with different channels and I used it in several services, but I'm not very clear about switching the Monolog channel in a controller.
In a service you just define the channel via the tags attribute in the service definition, but how can I do this in a controller or even better in a specific action?
I know that a possible solution would be this: Symfony 2 : Log into a specific file
But it seems overkill to define two new services just for logging to a custom file.
The only way to do this is to define your controller as a service and inject a custom logger with a custom channel.
Since the channels are created automatically there is currently no other way, but it's an interesting request and you're not the first, so I created an issue on MonologBundle to allow the definition of channels at the bundle configuration level. That way you could just fetch the proper logger from the controller using $this->get('monolog.logger.mychannel') (which you can already do if the channel exists, but not if you want a custom channel for the controller that nothing else uses).
Update:
As of symfony/monolog-bundle 2.4.0 you can define additional channels as:
monolog:
channels: ["foo", "bar"]
Then you can retrieve it as $this->get('monolog.logger.mychannel')
I know that this is an older post, but I ran into a similar need using symfony/monolog-bundle 2.1.x. I couldn't seem to find exactly what I needed in other threads, so I'm documenting my solution here, which was to create a logger container that used a custom channel.
In config.yml
monolog:
handlers:
user_actions:
type: stream
path: "%kernel.logs_dir%/%kernel.environment%-user-actions.log"
level: info
channels: [user_actions]
In my bundle's services.yml
acme.logger.user_actions:
class: Acme\MyBundle\Monolog\UserActionsLogger
arguments: ['#logger']
tags:
- { name: monolog.logger, channel: user_actions }
In src/Acme/MyBundle/Monolog/UserActionsLogger.php
<?php
namespace Acme\MyBundle\Monolog;
class UserActionsLogger
{
public $logger;
public function __construct($logger)
{
$this->logger = $logger;
}
}
Then you can either inject the logger container into another service with:
acme.user.authenticationhandler:
class: %acme.user.authenticationhandler.class%
public: false
arguments: ['#router', '#security.context', '#acme.logger.user_actions']
Or, you could selectively use the logger container as a service in any controller:
$userActionsLogger = $this->get('acme.logger.user_actions');
Then you can access the actual logger by:
$userActionsLogger->logger->info('A thing happened!')
I am currently using symfony/monolog-bundle 2.3.0 and the following code works.
Configuration in config.yml
monolog:
handlers:
main:
type: stream
path: %kernel.logs_dir%/%kernel.environment%.log
level: info
doctrine:
type: stream
path: %kernel.logs_dir%/doctrine_%kernel.environment%.log
level: debug
channels: doctrine
On Controllers
$doctrineLogger = $this->get('monolog.logger.doctrine');
Hope it helps.

Categories