Hello I coopied the example for using two different database connections from the Symfony2 documentation: Symfony2 multiple connections documentation
So however Symfony does not find the the costumer entity manager.
(The parameters are defined properly)
doctrine:
dbal:
default_connection: default
connections:
default:
driver: "%database_driver%"
host: "%database_host%"
port: "%database_port%"
dbname: "%database_name%"
user: "%database_user%"
password: "%database_password%"
charset: UTF8
customer:
driver: "%database_driver%"
host: "%database_host2%"
port: "%database_port2%"
dbname: "%database_name2%"
user: "%database_user2%"
password: "%database_password2%"
charset: UTF8
orm:
default_entity_manager: default
entity_managers:
default:
connection: default
mappings:
AppBundle: ~
customer:
connection: customer
mappings:
AppBundle: ~
The Controller looks like this:
class DefaultController extends Controller
{
/**
* #Route("/", name="homepage")
*/
public function indexAction(Request $request)
{
$em = $this->get('doctrine')->getManager();
$em = $this->get('doctrine')->getManager('default');
$em = $this->get('doctrine.orm.default_entity_manager');
// Both of these return the "customer" entity manager
$customerEm = $this->get('doctrine')->getManager('customer');
$customerEm = $this->get('doctrine.orm.customer_entity_manager');
return $this->render('default/index.html.twig', array(
'base_dir' => realpath($this->container->getParameter('kernel.root_dir').'/..'),
));
}
I should get the costumer entity manager, but however Symfony throws an invalid argument exception with the message.
[2015-10-19 23:19:18] request.CRITICAL: Uncaught PHP Exception
InvalidArgumentException: "Doctrine ORM Manager named "customer" does
not exist." at /srv/www/htdocs/symfony/my_project_name/app/cache
/prod/classes.php line 7344 {"exception":"[object]
(InvalidArgumentException(code: 0): Doctrine ORM Manager named
\"customer\" does not exist. at /srv/www/htdocs/symfony/my_project_name
/app/cache/prod/classes.php:7344)"} []
I cleaned the cache with php app/console cache:clear but this does not help.
Artamiel had the right answer in a comment:
Symfony2 Doctrine ORM Manager named "customer" does not exist
cache:clear clears the dev environment by default, but looking at your error log, you receive the error in your prod environment. To clear the cache on your production environment, add -e prod flag, like this cache:clear -e prod and refresh your page.
First, I think, one declaration of entity manager in your controller is enough:
/ *** /
public function indexAction(Request $request)
{
$em = $this->get('doctrine')->getManager('default');
$customerEm = $this->get('doctrine')->getManager('customer');
/ *** /
}
Second, are you sure that you can declare the same bundle in your mapping configuration (AppBundle: ~ in this case) ?
Related
This is my context:
I have two symfony REST API projects, and I want to do a relation between both projects. Each project uses his own database, entities and controllers.
From project 1 (client-api), I need to get access to entities of project 2 (product-api).
I have tried to use DoctrineRestDriver
Firstly, I have configured the config.yml file of client-api project:
doctrine:
dbal:
default_connection: default
connections:
default:
driver: "%database_driver%"
host: "%database_host%"
port: "%database_port%"
dbname: "%database_name%"
user: "%database_user%"
password: "%database_password%"
memory: "%database_memory%"
path: "%database_path%"
charset: UTF8
product_api:
driver_class: "Circle\\DoctrineRestDriver\\Driver"
host: "http://localhost"
port: 8000
user:
password:
options:
authentication_class: "HttpAuthentication"
orm:
default_entity_manager: default
entity_managers:
default:
connection: default
mappings:
AppBundle:
product_api:
connection: product_api
mappings:
AppBundle:
I want to read a country (id = 1) from the product-api project, so I have created this controller function on client-api project:
/**
* #Route("/countries", name="countries_other_api")
*/
public function getTheCountriesFromOtherApi()
{
$em = $this->getDoctrine()->getManager('product_api');
$country = $em->find("AppBundle\Entity\Country", 1);
}
But I'm getting the eror:
Class 'AppBundle\Entity\Pais' does not exist
Where is my problem ? How can I get access from symfony project 1 to symfony project 2 ?
Thanks.
So, you have 2 services. Each of service is responsible for its own entities. And you want service1 to have access directly to DB of service2...
My opinion is that you try to solve things in wrong way. If you want to get entities from service2 you should use REST API of service2 because you need to reimplement service2 logic in service1.
How to do it in better way? Create RestApi Client library for service2 and add it to service1 composer.json file. Dont forget to use authentication (hardcoded API keys or JWT...).
So, answer to your question 'where is problem?' I can say problem is in solution that you want to implement.
My multi-tenant-app uses a master database, that holds information about tenants (like name, etc.) and a app-specific database per tenant.
I configured a master and some_tenant connection and entity manager in the doctrine section inside config.yml.
This gives me access to the master database from a controller (eg. for validating and getting tenant information for some_tenant based on the subdomain some_tenant.my-app.com). And it lets me use a tenant-specific database and entity manager during the application life-cycle.
The doctrine section in my config looks like this:
doctrine:
dbal:
default_connection: 'master'
connections:
master:
driver: pdo_mysql
host: "%database_host%"
port: "%database_port%"
dbname: "%database_name%"
user: "%database_user%"
password: "%database_password%"
charset: UTF8
some_tenant:
driver: pdo_mysql
host: "%database_host_some_tenant%"
port: "%database_port_some_tenant%"
dbname: "%database_name_some_tenant%"
user: "%database_user_some_tenant%"
password: "%database_password_some_tenant%"
charset: UTF8
orm:
auto_generate_proxy_classes: "%kernel.debug%"
entity_managers:
master:
connection: master
mappings:
BEMultiTenancyBundle: ~
some_tenant:
connection: some_tenant
mappings:
AppBundle: ~
Here comes the part, which I am unhappy with and cannot find a solution:
First of all, tenants will be more than 20. And it starts to get messy, altering the doctrine config this way.
Then there is another config file, called tenants.yml which holds more information like enabled/disabled app-features, tenant-specific themes, etc.
The file is loaded, validated using the Config Component, and a container parameter is set, so that tenants configurations are available app-wide.
I would like to store the database credentials also in that file.
I want to create connections and entity managers based on that config. One per each tenant, which can be used during the app life-cycle.
I need to have them available also at the console command bin/console doctrine:schema:update --em=some_tenant for updating each tenant's database schem and bin/console doctrine:schema:update --em=master for updating the master database scheme.
By now I guess, the only way to achieve this is to add configuration parameters to the doctrine section programmatically after the AppBundle is loaded, and before the doctrine registry is constructed with the given managers and connections.
But I cannot even find a point, where I could achive this.
Is there another way to get to point 1 and 2?
Even though there is a similiar question, which I am not sure if it is exactly about the same problem and is about 3 years old, I wanted to post this question with a bit more explanation.
The solution in comments is a straight way easy solution and it will work. The other solution I've ever meet is to dynamically replace tenant database credentails using some external conditions, i.e request HOST.
You can decorate or extend the connection factory with a service in a way, that having the request stack available (or providing the domain with ENV or console argument for other SAPI's) you can have the same entity manager (even default!) being configured on demand.
on a brief look this would look like
use Doctrine\Bundle\DoctrineBundle\ConnectionFactory;
use Doctrine\Common\EventManager;
use Doctrine\DBAL\Configuration;
use Symfony\Component\HttpFoundation\RequestStack;
class DynamicConnectionFactory extends Factory
{
/** #var RequestStack */
private $requestStack;
public function __construct(array $types, RequestStack $stack)
{
parent::__construct($types);
$this->requestStack = $stack;
}
public function createConnection(array $params, Configuration $config = null, EventManager $eventManager = null, array $mappingTypes = array())
{
$host = $this->requestStack->getMasterRequest()->getHost();
$params = $this->replaceParamsForHost(array $params, $host);
return parent::createConnection($params, $config, $eventManager, $mappingTypes);
}
private function replaceParamsForHost(array $params, $host)
{
//do your magic, i.e parse config or call Memcache service or count the stars
return array_replace($params, ['database' => $host]);
}
}
I think that, To manage multi-tenant with symfony 2/3.
We can config auto_mapping: false for ORM of doctrine.
file: config.yml
doctrine:
dbal:
default_connection: master
connections:
master:
driver: pdo_mysql
host: '%master_database_host%'
port: '%master_database_port%'
dbname: '%master_database_name%'
user: '%master_database_user%'
password: '%master_database_password%'
charset: UTF8
tenant:
driver: pdo_mysql
host: '%tenant_database_host%'
port: '%tenant_database_port%'
dbname: '%tenant_database_name%'
user: '%tenant_database_user%'
password: '%tenant_database_password%'
charset: UTF8
orm:
default_entity_manager: master
auto_generate_proxy_classes: "%kernel.debug%"
entity_managers:
master:
connection: master
auto_mapping: false
mappings:
AppBundle:
type: yml
dir: Resources/master/config/doctrine
tenant:
connection: tenant
auto_mapping: false
mappings:
AppBundle:
type: yml
dir: Resources/tenant/config/doctrine
After that, we cannot handle connection of each tenant by override connection info in request_listener like article: http://mohdhallal.github.io/blog/2014/09/12/handling-multiple-entity-managers-in-doctrine-the-smart-way/
I hope that, this practice can help someone working with multi-tenant
Regards,
Vuong Nguyen
I am trying to integrate Redis with my Symfony API, I found this bundle : RedisBundle
I installed it and configured so that I can cache Doctrine like so config.yml:
# Doctrine Configuration
doctrine:
dbal:
driver: pdo_mysql
host: "%database_host%"
port: "%database_port%"
dbname: "%database_name%"
user: "%database_user%"
password: "%database_password%"
charset: UTF8
orm:
auto_generate_proxy_classes: "%kernel.debug%"
naming_strategy: doctrine.orm.naming_strategy.underscore
auto_mapping: true
metadata_cache_driver: redis
# enable query caching
query_cache_driver: redis
snc_redis:
# configure predis as client
clients:
default:
type: predis
alias: default
dsn: redis://localhost
doctrine:
type: predis
alias: doctrine
dsn: redis://localhost
# configure doctrine caching
doctrine:
metadata_cache:
client: doctrine
entity_manager: default
document_manager: default
result_cache:
client: doctrine
entity_manager: [default]
query_cache:
client: doctrine
entity_manager: default
In my FetchBookRepository I am trying to use RedisCache there:
<?php
namespace BooksApi\BookBundle\Repositories;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Query\QueryException;
use Snc\RedisBundle\Doctrine\Cache\RedisCache;
use Predis\Client;
class FetchBookRepository
{
/**
* #var EntityManager
*/
public $em;
/**
* #param EntityManager $entityManager
*/
public function __construct(
EntityManager $entityManager
){
$this->em = $entityManager;
}
/**
* #param $id
* #return null|object
* #throws QueryException
*/
public function fetchBook($id)
{
$predis = new RedisCache();
$predis->setRedis(new Client);
$cache_lifetime= 3600;
try {
$book = $this->em->getRepository('BooksApiBookBundle:BooksEntity')
->find($id);
} catch (\Exception $ex) {
$this->em->close();
throw new QueryException('003', 502);
}
return $book;
}
}
I called the RedisCahce and Client classes but how do I now use it with my query..? I cant really find much on Google in regards to Symfony & Redis.
UPDATE:
When I use redis-cli and type in MONITOR i get this output:
1454337749.112055 [0 127.0.0.1:60435] "GET" "[BooksApi\\BookBundle\\Entity\\BooksEntity$CLASSMETADATA][1]"
Your Redis config looks OK.
You are using Redis to cache Meatada (Doctrine collected about Entities mappings, etc) and Query (DQL to SQL).
To use Redis as Cache for Results you must write custom Query and define that it is cacheable. Please follow the Doctrine manual http://docs.doctrine-project.org/en/latest/reference/caching.html#result-cache and this GitHub issue https://github.com/snc/SncRedisBundle/issues/77
In my Symfony2 project, I need to do some work in database with a Command.
When I launch it, I have this error :
[Exception]
There is no default connection
I don't understand why ?
My code :
1. $this->output = $output;
2. $this->writeln( 'ImportBase' );
3. $importBase = Model\ImportBase::builder()
->whereEgal('termine', 0)
->limit(1)
->getObject();
For information, there is just one connection in my project.
Also, I do not use Doctrine but ORM (I guess ? This is not my project)
Do you have any idea ? I can't find anything...
EDIT :
config.yml :
doctrine:
dbal:
default_connection: default
connections:
default:
driver: "%database_driver%"
host: "%database_host%"
port: "%database_port%"
dbname: "%database_name%"
user: "%database_user%"
password: "%database_password%"
charset: UTF8
orm:
auto_generate_proxy_classes: "%kernel.debug%"
auto_mapping: true
Parameters.yml
parameters:
database_driver: pdo_mysql
database_host: 127.0.0.1
database_port: null
database_name: [...]
database_user: [...]
database_password: [...]
Model :
<?php
namespace xxx\xxxhBundle\Model;
use xxx\ORM\Model;
class ImportBase extends Model
{
protected static $table_name = 'import_base';
protected static $primary_key = 'import_base_id';
}
Builder in Model file
/**
* Get command builder for the class
*
* #return DbCommandBuilder builder
*/
public static function builder() {
if( static::$table_name == null )
throw new \Exception('Canot get builder, table_name is not set');
$builder = static::dbConnection()->builder( static::tableName(), static::$builder_class );
$builder->setFetchClassName( get_called_class() );
return $builder;
}
That seems a little strange... I don't notice anything wrong based on the configuration you've supplied.
However, since you appear to only have one dbal connection, you could simply use the "terser" configuration:
doctrine:
dbal:
driver: "%database_driver%"
host: "%database_host%"
port: "%database_port%"
dbname: "%database_name%"
user: "%database_user%"
password: "%database_password%
charset: UTF8
orm:
auto_generate_proxy_classes: "%kernel.debug%"
auto_mapping: true
Hope this helps :)
I'm trying to do a schema update into multiple databases, depending on the config environment used the changes will be done in a database or other.
I was trying to add an own --env parameter to the doctrine script:
vendor/bin/doctrine --env=dev orm:schema-tool:update --force -vvv --dump-sql
And inside my cli-config.php I read the argument and select my database, but after that, it fails:
[RuntimeException]
The "--env" option does not exist.
Exception trace:
() at /var/www/consupermiso2-frontend/vendor/symfony/console/Input/ArgvInput.php:213
Symfony\Component\Console\Input\ArgvInput->addLongOption() at /var/www/consupermiso2-frontend/vendor/symfony/console/Input/ArgvInput.php:152
Symfony\Component\Console\Input\ArgvInput->parseLongOption() at /var/www/consupermiso2-frontend/vendor/symfony/console/Input/ArgvInput.php:86
Symfony\Component\Console\Input\ArgvInput->parse() at /var/www/consupermiso2-frontend/vendor/symfony/console/Input/Input.php:61
Symfony\Component\Console\Input\Input->bind() at /var/www/consupermiso2-frontend/vendor/symfony/console/Command/Command.php:231
Symfony\Component\Console\Command\Command->run() at /var/www/consupermiso2-frontend/vendor/symfony/console/Application.php:878
Symfony\Component\Console\Application->doRunCommand() at /var/www/consupermiso2-frontend/vendor/symfony/console/Application.php:195
Symfony\Component\Console\Application->doRun() at /var/www/consupermiso2-frontend/vendor/symfony/console/Application.php:126
Symfony\Component\Console\Application->run() at /var/www/consupermiso2-frontend/vendor/doctrine/orm/lib/Doctrine/ORM/Tools/Console/ConsoleRunner.php:60
Doctrine\ORM\Tools\Console\ConsoleRunner::run() at /var/www/consupermiso2-frontend/vendor/doctrine/orm/bin/doctrine.php:66
include() at /var/www/consupermiso2-frontend/vendor/doctrine/orm/bin/doctrine:4
orm:schema-tool:update [--complete] [--dump-sql] [-f|--force]
How can I choose in which database I'm going to work using the cli tool?
So lets assume that you have an application which has its own database, plus it uses a seperate database to store all of its help system data. This help database could be shared across different installations of the application on the same server.
In Symfony its easy to specify different entity managers so you can pick and choose which one to use. This can be done easily from command line, or from the controllers.
in your config.yml file, you would have something like this (the parameters for these will sit in parameters.yml):
doctrine:
dbal:
default_connection: default
connections:
default:
driver: "%database_driver%"
host: "%database_host%"
port: "%database_port%"
dbname: "%database_name%"
user: "%database_user%"
password: "%database_password%"
charset: UTF8
help:
driver: "%database_driver2%"
host: "%database_host2%"
port: "%database_port2%"
dbname: "%database_name2%"
user: "%database_user2%"
password: "%database_password2%"
charset: UTF8
orm:
default_entity_manager: default
entity_managers:
default:
connection: default
mappings:
MainBundle: ~
help:
connection: customer
mappings:
HelpBundle: ~d
you will then be able to specify which database to use from command line like this:
php app/console doctrine:schema:update --force --em=help
or in the controller something like this:
$entityManager = $this->get('doctrine')->getManager('help');
if you need more info, have a look a the symfony docs
Oks, I've solved my self as follows:
In your config/cli-config.php file add the following code before loading your configuration file:
$environmentName = null;
foreach ($_SERVER['argv'] as $index => $arg) {
$e = explode('=', $arg);
$key = str_replace('-', '', $e[0]);
if ('em' == $key) {
$environmentName = $e[1];
unset($_SERVER['argv'][$index]);
}
}
if (empty($environmentName)) {
throw new EmptyEnvironmentException('Try adding --em=[environment] option');
}
$environmentFilePath = PROJECT_PATH . "/config/$environmentName.yml";
if (!is_readable($environmentFilePath)) {
throw new UnexpectedConfigFileException($environmentName);
}
$config = new PhConfig($environmentFilePath);
So, you must read the given property and remove it from $_SERVER['argv'], or doctrine will try to parse it throwing an exception.