iam new to symfony and created some project based on 4.2 as i have to dynamically switch the db and there seems to be a bug in this version, i followed some instruction to setup a wrapper class for connecting to the db, this works fine. But iam struggeling with getting the doctrince method getConnections() here to work, to be able to double check the sended parameter against my db config. Everything i tried by initializing the doctrine as service container etc. doesn't work.
Hope someone could give me a hint, also my first post, so please no hate (:
Greetings
doctrine:
dbal:
default_connection: db_name
connections:
my_connection:
wrapper_class: App\Doctrine\DynamicConnection
url: '%env(DATABASE_URL)%'
driver: 'pdo_mysql'
server_version: '5.7'
charset: utf8mb4
services:
# default configuration for services in *this* file
_defaults:
public: false
autowire: true # Automatically injects dependencies in your services.
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
App\Doctrine\:
resource: '../src/Doctrine'
tags: ['doctrine.service_arguments']
doctrine.entity_manager:
public: true
class: App\Doctrine\DynamicConnection
arguments: [ '#doctrine.orm.entity_manager' ]
namespace App\Doctrine;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Driver;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\DependencyInjection\ContainerBuilder;
class DynamicConnection extends Connection
{
public function __construct(array $params = array(), Driver $driver = null, $config = null, $eventManager = null)
{
#$request = Request::createFromGlobals();
#$dbname = $request->query->get('db_name');
$containerBuilder = new ContainerBuilder();
var_dump($containerBuilder->getServiceIds());
$doctrine = $containerBuilder->get('doctrine.entity_manager');
Related
I'm trying to create a service, which can be injected anywhere. For this I am trying to pass as argument the HttpClient component of Symfony 4.3
I show you the service
https://i.stack.imgur.com/2384M.png
<?php
namespace App\Service\Callback;
use Symfony\Component\HttpClient\HttpClient;
class Back
{
private $client;
public function __construct(HttpClient $httpClient)
{
$this->client = $httpClient::create();
}
public function sendCallback ( $method, $urlCallback, $option)
{
$response = $this->client->request($method,$urlCallback,$option);
$statusCode = $response->getStatusCode();
return $statusCode;
}
}
Well, I'm trying to load it in the services.yml
# This file is the entry point to configure your own services.
# Files in the packages/ subdirectory configure your dependencies.
# Put parameters here that don't need to change on each machine where the app is deployed
# https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
parameters:
locale: 'en'
base_url_front: '%env(BASE_URL_FRONT)%'
mobile_type: 2
services:
# default configuration for services in *this* file
_defaults:
autowire: true # Automatically injects dependencies in your services.
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
Nexy\Slack\Client: '#nexy_slack.client'
Symfony\Component\HttpClient\HttpClient: '#http.client'
# makes classes in src/ available to be used as services
# this creates a service per class whose id is the fully-qualified class name
App\:
resource: '../src/*'
exclude: '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}'
# controllers are imported separately to make sure services can be injected
# as action arguments even if you don't extend any base controller class
App\Controller\:
resource: '../src/Controller'
tags: ['controller.service_arguments']
App\Service\Models\:
resource: '../src/Service/Models'
tags: ['#doctrine.orm.entity_manager','#nexy_slack.client']
slack_client:
class: 'App\Service\SlackClient'
autowire : true
arguments: ['#nexy_slack.client','#kernel']
public : true
callback_client:
class: 'App\Service\Callback\Back'
autowire: true
arguments: ['#http.client']
public: true
App\Service\Apiclient\AteneaService:
arguments: ["%kernel.environment%"]
App\Service\Apiclient\UpmService:
arguments: ["%kernel.environment%"]
App\Service\Apiclient\HermesService:
arguments: ["%kernel.environment%"]
App\Service\Socket\:
resource: '../src/Service/Socket'
tags: ['#kernel','#nexy_slack.client']
The problem is that if I run php bin / console debug: autowiring in the terminal, to know if I created it, it returns the following error :
You have requested a non-existent service "http.client".
In the end what I want to achieve is something like this:
public function getClient(Back $back)
{
$back->sendCallback('GET','http://vro-back.localhost:8888/callback/test');
}
But I can not because I can not inject it.
At the end if you look at the services.yml, I'm trying to create an alias for an HttpClient component, so I can pass it as an argument to the constructor of the Back class
And the route that I'm trying to load, exists ...
Symfony \ Component \ HttpClient \ HttpClient;
This is the component with which I am trying to work
https://symfony.com/doc/current/components/http_client.html
I would appreciate any help.
You need to type-hint the interface instead
public function __construct(HttpClientInterface $httpClient)
{
$this->httpClient = $httpClient;
}
And remove service.yaml configuration
https://symfony.com/doc/current/components/http_client.html
Symfony can't find service for fos_elastica
Service "fos_elastica.finder.app.user" not found: even though it exists in the app's container, the container inside "App\Controller\DevController" is a smaller service locator that only knows about the "doctrine", "form.factory", "http_kernel", "parameter_bag", "request_stack", "router", "security.authorization_checker", "security.csrf.token_manager", "security.token_storage", "session" and "twig" services. Unless you need extra laziness, try using dependency injection instead. Otherwise, you need to declare it using "DevController::getSubscribedServices()".
my config
# Read the documentation: https://github.com/FriendsOfSymfony/FOSElasticaBundle/blob/master/Resources/doc/setup.md
fos_elastica:
clients:
default: { host: localhost, port: 9200 }
# indexes:
# app: ~
indexes:
app:
client: default
types:
user:
properties:
username: ~
# mappings:
# email: ~
persistence:
# the driver can be orm, mongodb, phpcr or propel
# listener and finder are not supported by
# propel and should be removed
driver: orm
model: App\Entity\User
provider: ~
listener: ~
finder: ~
my controller:
/**
* #Route("/search")
*/
public function searchElastic(){
/** var array of App\Entity\User */
$finder = $this->container->get('fos_elastica.finder.app.user');
return new response('N/A');
}
command php bin/console fos:elastica:populate didn't throw any errors and in phpstorm it isn't highlighted (it mean phpstorm found it)
Please help me.
You should use Dependency Injection like so:
Add use statement in the controller class use FOS\ElasticaBundle\Manager\RepositoryManagerInterface;, then your action should look like this:
/**
* #Route("/search")
*/
public function searchElastic(RepositoryManagerInterface $finder) {
$someResult = $finder->getRepository(User::class)->find(...);
return new response('N/A');
}
I'm trying to configure a service inside a bundle. This service needs some parameters from the.env file but I can't declare these parameters in the service. Here's my code:
src/Dfc2/WsBundle/Services/WsManager/WsManager.yaml
parameters:
wsAdminUser: '%env(WSADMIN_USER)%'
wsAdminPassword: '%env(WSADMIN_PASSWORD)%'
services:
_defaults:
autowire: true
autoconfigure: true
public: false
WsManager:
public: true
class: App\Dfc2\WsBundle\Services\WsManager\WsManager
arguments:
$env: '%kernel.environment%'
$wsAdminUser: '%wsAdminUser%'
$wsAdminPassword: '%wsAdminPassword%'
src/Dfc2/WsBundle/Services/WsManager/WsManager.php constructor:
public function __construct($env, RequestStack $requestStack, SessionInterface $session, string $wsAdminUser, string $wsAdminPassword)
{
$this->environement = $env;
$this->wsAdminUser = $wsAdminUser;
$this->wsAdminPassword = $wsAdminPassword;
$this->session = $session;
$this->baseUrl = $requestStack->getCurrentRequest()->getBaseUrl() . WsParameters::URL_SUFFIX;
$this->setBaseUrl();
}
And this is the error message I get.
Cannot autowire service "App\Dfc2\WsBundle\Services\WsManager\WsManager": argument "$wsAdminUser" of method "__construct()" must have a type-hint or be given a value explicitly.
I don't understand what's wrong. Can you help me?
Thanks to Mathieu Dormeval and Cerad,
I changed my service definition like this and now it works:
services:
App\Dfc2\WsBundle\Services\WsManager\WsManager:
autowire: false
public: true
arguments:
$env: '%kernel.environment%'
$requestStack: '#request_stack'
$session: '#session'
$wsAdminUser: '%wsAdminUser%'
$wsAdminPassword: '%wsAdminPassword%'
Please help me with config Console App, in first - config
#!/usr/bin/env php
<?php
use ....
...
$container = new ContainerBuilder();
$config = new YamlFileLoader($container, new FileLocator(__DIR__));
$config->load('config.yml');
$output = $container->get('symfony.console_output');$logger = $container->get('logger');
//I want automatic injection!!!!
$helloCommand = new HelloCommand($container, $logger);
$application = $container->get('symfony.application');
$application->add($helloCommand);
$application->run(null, $output);
And my config.yml
services:
logger:
class: Symfony\Component\Console\Logger\ConsoleLogger
arguments:
- '#symfony.console_output'
symfony.application:
class: Symfony\Component\Console\Application
calls:
//by this variant autowire not working
- [add, [ '#app.command.hello_command' ]]
- [setDispatcher, ['#symfony.event_dispatcher']]
...
app.command.hello_command:
class: App\Command\HelloCommand
autowire: true
tags:
- { name: console.command }
So my HelloCommand has constructor with ContainerInterface and LoggerInterface and it work only if i set this arguments directly, other i have error about wrong constructor
Or may be exists another way for configuration with config.yml
for only logger - its will be simple by set ['#logger'] as arguments, but how can i set current container as argument?
Or i`ll have to install full symfony with httpkernel (but it does not need)
HelloCommand
http://pastebin.com/VRr3FM7Q
THE DECISION
app.command.hello_command:
class: App\Command\HelloCommand
arguments:
- '#service_container'
- '#logger'
tags:
- { name: console.command }
The problem lies in how you configure your command:
app.command.hello_command:
class: App\Command\HelloCommand
autowire: true
tags:
- { name: console.command }
This misses the 2 constructor arguments required: $container, $logger and is probably why you get the exception. You can add constructor arguments like this:
app.command.hello_command:
class: App\Command\HelloCommand
arguments:
- '#service_container'
- '#logger'
[...]
I'm not sure if the id for the service_container is right. I never pass the container or make things ContainerAware, but you get the general idea. ;)
I asked about using multiple entity manager for FOSUserBundle before, and it turns out that FOSUserBundle has (partially) supported that. All I need to do is to specify the connection / manager I want to use in the model_manager_name parameter, as explained here
fos_user:
# ........
model_manager_name: account1
Sample app/config/config.yml
With this FOSUserBundle will use account1 connection, and use user information in that connection's database.
doctrine:
dbal:
default_connection: default
connections:
account2:
dbname: account2
user: account2
password: password2
driver: pdo_mysql
host: localhost
port: ~
charset: UTF8
account1:
dbname: account1
user: account1
password: password1
driver: pdo_mysql
host: localhost
port: ~
charset: UTF8
default:
dbname: account
user: account
password: password
driver: pdo_mysql
host: localhost
port: ~
charset: UTF8
My app require that when a user goes to (for example) http://myapp.com/a/account1, the app will use account1 connection, and going to http://myapp.com/a/account2 will use account2's connection. For my application's logic, this is easily done from my controllers as I could use something like the following;
$em = $this->get('doctrine')->getManager('account2');
$repository = $this->get('doctrine')->getRepository($class, 'account2')
For the login part though, it's not that easy. FOSUserBundle runs as a service container, and I don't know where/how to dynamically change the model_manager_name's value. I do know though that in FOS\UserBundle\DependencyInjection\FOSUserExtension I can manually change its value the following way;
class FOSUserExtension extends Extension
{
public function load(array $configs, ContainerBuilder $container)
{
$processor = new Processor();
$configuration = new Configuration();
$config = $processor->processConfiguration($configuration, $configs);
$config['model_manager_name'] = 'account2';
// .................
Any thoughts?
The configuration is stored inside the container, in the fos_user.model_manager_name to be exact.
You can write a compiler pass. This will be executed just before freezing the container, it is the last place where you can change the container and it is the place to change the container based on other services.
Your compiler pass will look like this:
// src/Acme/DemoBundle/DependencyInjection/Compiler/ChangeModelManagerPass.php
namespace Acme\DemoBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
class ChangeModelManagerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
$request = $container->get('request');
$uri = $request->getUri();
// check if the uri matches some pattern which will cause a change in the
// `model_manager_name` setting
if (...) {
// ... do some stuff to get the correct model manager name
// set the setting
$container->setParameter('fos_user.model_manager_name', ...);
}
}
}
Read more about compiler passes in the docs or in this great blog post by Richard Miller.